From 72de959221b44eb3d3533fd5624957cb1d29f058 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 6 Jun 2017 15:54:08 +0200 Subject: Remove notifications for deleted messages. --- src/modules/statuses.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/modules/statuses.js') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 051ec71b..98a8d16d 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -242,6 +242,10 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us const uri = deletion.uri updateMaxId(deletion) + // Remove possible notification + const status = find(allStatuses, {uri}) + remove(state.notifications, ({action: {id}}) => status.id) + remove(allStatuses, { uri }) if (timeline) { remove(timelineObject.statuses, { uri }) -- cgit v1.2.3-70-g09d2 From 9982296866f0592747064d3cb6ddfac0fce516b1 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Wed, 7 Jun 2017 17:03:14 +0200 Subject: Don't crash on unknown status deletion. --- src/modules/statuses.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/modules/statuses.js') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 98a8d16d..2546a2de 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -244,6 +244,10 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us // Remove possible notification const status = find(allStatuses, {uri}) + if (!status) { + return + } + remove(state.notifications, ({action: {id}}) => status.id) remove(allStatuses, { uri }) -- cgit v1.2.3-70-g09d2 From 090148ef6051ec2399fe47281db9f73955297d97 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 12 Jun 2017 16:00:46 +0200 Subject: Start fetching user timelines. --- src/components/user_profile/user_profile.js | 14 ++++++++++---- src/components/user_profile/user_profile.vue | 2 +- src/modules/api.js | 11 ++++++++++- src/modules/statuses.js | 11 +++++++++++ src/services/api/api.service.js | 19 +++++++++++++++---- .../backend_interactor_service.js | 4 ++-- .../timeline_fetcher/timeline_fetcher.service.js | 10 ++++++---- 7 files changed, 55 insertions(+), 16 deletions(-) (limited to 'src/modules/statuses.js') diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 4d52bc95..4f35cf27 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -1,12 +1,18 @@ import UserCardContent from '../user_card_content/user_card_content.vue' -import { find } from 'lodash' const UserProfile = { + created () { + this.$store.dispatch('startFetching', ['user', this.userId]) + }, + destroyed () { + this.$store.dispatch('stopFetching', ['user', this.userId]) + }, computed: { + userId () { + return this.$route.params.id + }, user () { - const id = this.$route.params.id - const user = find(this.$store.state.users.users, {id}) - return user + return this.$store.state.users.usersObject[this.userId] } }, components: { diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue index 11a61bfc..fe693c9d 100644 --- a/src/components/user_profile/user_profile.vue +++ b/src/components/user_profile/user_profile.vue @@ -1,5 +1,5 @@ diff --git a/src/modules/api.js b/src/modules/api.js index a32adfde..e61382eb 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -1,4 +1,5 @@ import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' +import {isArray} from 'lodash' const api = { state: { @@ -18,9 +19,17 @@ const api = { }, actions: { startFetching (store, timeline) { + let userId = false + + // This is for user timelines + if (isArray(timeline)) { + userId = timeline[1] + timeline = timeline[0] + } + // Don't start fetching if we already are. if (!store.state.fetchers[timeline]) { - const fetcher = store.state.backendInteractor.startFetching({timeline, store}) + const fetcher = store.state.backendInteractor.startFetching({timeline, store, userId}) store.commit('addFetcher', {timeline, fetcher}) } }, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 2546a2de..372567c5 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -32,6 +32,17 @@ export const defaultState = { minVisibleId: 0, loading: false }, + user: { + statuses: [], + statusesObject: {}, + faves: [], + visibleStatuses: [], + visibleStatusesObject: {}, + newStatusCount: 0, + maxId: 0, + minVisibleId: 0, + loading: false + }, publicAndExternal: { statuses: [], statusesObject: {}, diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 1c5e281e..3715a211 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -18,6 +18,7 @@ const FOLLOWING_URL = '/api/friendships/create.json' const UNFOLLOWING_URL = '/api/friendships/destroy.json' const QVITTER_USER_PREF_URL = '/api/qvitter/set_profile_pref.json' const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json' +const QVITTER_USER_TIMELINE_URL = '/api/qvitter/statuses/user_timeline.json' // const USER_URL = '/api/users/show.json' const oldfetch = window.fetch @@ -98,24 +99,34 @@ const setUserMute = ({id, credentials, muted = true}) => { }) } -const fetchTimeline = ({timeline, credentials, since = false, until = false}) => { +const fetchTimeline = ({timeline, credentials, since = false, until = false, userId = false}) => { const timelineUrls = { public: PUBLIC_TIMELINE_URL, friends: FRIENDS_TIMELINE_URL, mentions: MENTIONS_URL, - 'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL + 'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL, + user: QVITTER_USER_TIMELINE_URL } let url = timelineUrls[timeline] + let params = [] + if (since) { - url += `?since_id=${since}` + params.push('since_id', since) } if (until) { - url += `?max_id=${until}` + params.push('max_id', until) + } + + if (userId) { + params.push(['user_id', userId]) } + const queryString = new URLSearchParams(params).toString() + url += `?${queryString}` + return fetch(url, { headers: authHeaders(credentials) }).then((data) => data.json()) } diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 74248bc0..f2d01c70 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -26,8 +26,8 @@ const backendInteractorService = (credentials) => { return apiService.unfollowUser({credentials, id}) } - const startFetching = ({timeline, store}) => { - return timelineFetcherService.startFetching({timeline, store, credentials}) + const startFetching = ({timeline, store, userId = false}) => { + return timelineFetcherService.startFetching({timeline, store, credentials, userId}) } const setUserMute = ({id, muted = true}) => { diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js index 24aef069..b28de9e7 100644 --- a/src/services/timeline_fetcher/timeline_fetcher.service.js +++ b/src/services/timeline_fetcher/timeline_fetcher.service.js @@ -14,7 +14,7 @@ const update = ({store, statuses, timeline, showImmediately}) => { }) } -const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false, showImmediately = false}) => { +const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false, showImmediately = false, userId = false}) => { const args = { timeline, credentials } const rootState = store.rootState || store.state const timelineData = rootState.statuses.timelines[camelCase(timeline)] @@ -25,14 +25,16 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false args['since'] = timelineData.maxId } + args['userId'] = userId + return apiService.fetchTimeline(args) .then((statuses) => update({store, statuses, timeline, showImmediately}), () => store.dispatch('setError', { value: true })) } -const startFetching = ({ timeline = 'friends', credentials, store }) => { - fetchAndUpdate({timeline, credentials, store, showImmediately: true}) - const boundFetchAndUpdate = () => fetchAndUpdate({ timeline, credentials, store }) +const startFetching = ({timeline = 'friends', credentials, store, userId = false}) => { + fetchAndUpdate({timeline, credentials, store, showImmediately: true, userId}) + const boundFetchAndUpdate = () => fetchAndUpdate({ timeline, credentials, store, userId }) return setInterval(boundFetchAndUpdate, 10000) } const timelineFetcher = { -- cgit v1.2.3-70-g09d2 From bda0a76c89cadc6251261a08575acf6986da1084 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Mon, 12 Jun 2017 16:30:56 +0200 Subject: Clear timeline on user change. --- src/components/user_profile/user_profile.js | 1 + src/modules/statuses.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'src/modules/statuses.js') diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 5eef2735..3d473592 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -3,6 +3,7 @@ import Timeline from '../timeline/timeline.vue' const UserProfile = { created () { + this.$store.commit('clearTimeline', { timeline: 'user' }) this.$store.dispatch('startFetching', ['user', this.userId]) }, destroyed () { diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 372567c5..0b4069c6 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -295,6 +295,21 @@ export const mutations = { oldTimeline.visibleStatusesObject = {} each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status }) }, + clearTimeline (state, { timeline }) { + const emptyTimeline = { + statuses: [], + statusesObject: {}, + faves: [], + visibleStatuses: [], + visibleStatusesObject: {}, + newStatusCount: 0, + maxId: 0, + minVisibleId: 0, + loading: false + } + + state.timelines[timeline] = emptyTimeline + }, setFavorited (state, { status, value }) { const newStatus = state.allStatusesObject[status.id] newStatus.favorited = value -- cgit v1.2.3-70-g09d2 From e663420260bc135f0851a996a67a87a947580bf4 Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Tue, 13 Jun 2017 12:01:47 +0200 Subject: Fix notification deletion. --- src/modules/statuses.js | 2 +- test/unit/specs/modules/statuses.spec.js | 33 +++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'src/modules/statuses.js') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 0b4069c6..c3753c5a 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -259,7 +259,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us return } - remove(state.notifications, ({action: {id}}) => status.id) + remove(state.notifications, ({action: {id}}) => id === status.id) remove(allStatuses, { uri }) if (timeline) { diff --git a/test/unit/specs/modules/statuses.spec.js b/test/unit/specs/modules/statuses.spec.js index 66d6cfd7..d25cc108 100644 --- a/test/unit/specs/modules/statuses.spec.js +++ b/test/unit/specs/modules/statuses.spec.js @@ -125,18 +125,19 @@ describe('The Statuses module', () => { it('removes statuses by tag on deletion', () => { const state = cloneDeep(defaultState) const status = makeMockStatus({id: 1}) + const otherStatus = makeMockStatus({id: 3}) status.uri = 'xxx' const deletion = makeMockStatus({id: 2, is_post_verb: false}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' - mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' }) + mutations.addNewStatuses(state, { statuses: [status, otherStatus], showImmediately: true, timeline: 'public' }) mutations.addNewStatuses(state, { statuses: [deletion], showImmediately: true, timeline: 'public' }) - expect(state.allStatuses).to.eql([]) - expect(state.timelines.public.statuses).to.eql([]) - expect(state.timelines.public.visibleStatuses).to.eql([]) - expect(state.timelines.public.maxId).to.eql(2) + expect(state.allStatuses).to.eql([otherStatus]) + expect(state.timelines.public.statuses).to.eql([otherStatus]) + expect(state.timelines.public.visibleStatuses).to.eql([otherStatus]) + expect(state.timelines.public.maxId).to.eql(3) }) it('does not update the maxId when the noIdUpdate flag is set', () => { @@ -323,28 +324,30 @@ describe('The Statuses module', () => { const user = { id: 1 } const state = cloneDeep(defaultState) const status = makeMockStatus({id: 1}) + const otherStatus = makeMockStatus({id: 3}) const mentionedStatus = makeMockStatus({id: 2}) mentionedStatus.attentions = [user] mentionedStatus.uri = 'xxx' + otherStatus.attentions = [user] - const deletion = makeMockStatus({id: 3, is_post_verb: false}) + const deletion = makeMockStatus({id: 4, is_post_verb: false}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' - mutations.addNewStatuses(state, { statuses: [status], user }) + mutations.addNewStatuses(state, { statuses: [status, otherStatus], user }) - expect(state.notifications.length).to.eql(0) + expect(state.notifications.length).to.eql(1) mutations.addNewStatuses(state, { statuses: [mentionedStatus], user }) - expect(state.allStatuses.length).to.eql(2) - expect(state.notifications.length).to.eql(1) - expect(state.notifications[0].status).to.eql(mentionedStatus) - expect(state.notifications[0].action).to.eql(mentionedStatus) - expect(state.notifications[0].type).to.eql('mention') + expect(state.allStatuses.length).to.eql(3) + expect(state.notifications.length).to.eql(2) + expect(state.notifications[1].status).to.eql(mentionedStatus) + expect(state.notifications[1].action).to.eql(mentionedStatus) + expect(state.notifications[1].type).to.eql('mention') mutations.addNewStatuses(state, { statuses: [deletion], user }) - expect(state.allStatuses.length).to.eql(1) - expect(state.notifications.length).to.eql(0) + expect(state.allStatuses.length).to.eql(2) + expect(state.notifications.length).to.eql(1) }) it('adds the message to mentions when you are mentioned', () => { -- cgit v1.2.3-70-g09d2 From 8e5d17a659b157f095ad3850ac3cdd2e537ac38b Mon Sep 17 00:00:00 2001 From: Roger Braun Date: Sun, 18 Jun 2017 19:19:17 +0200 Subject: Use tags array in status if available. --- src/modules/statuses.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/modules/statuses.js') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index c3753c5a..084800fa 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -1,4 +1,4 @@ -import { remove, slice, sortBy, toInteger, each, find, flatten, maxBy, last, merge, max, isArray } from 'lodash' +import { includes, remove, slice, sortBy, toInteger, each, find, flatten, maxBy, last, merge, max, isArray } from 'lodash' import apiService from '../services/api/api.service.js' // import parse from '../services/status_parser/status_parser.js' @@ -68,11 +68,15 @@ export const defaultState = { } } +const isNsfw = (status) => { + const nsfwRegex = /#nsfw/i + return includes(status.tags, 'nsfw') || !!status.text.match(nsfwRegex) +} + export const prepareStatus = (status) => { // Parse nsfw tags if (status.nsfw === undefined) { - const nsfwRegex = /#nsfw/i - status.nsfw = !!status.text.match(nsfwRegex) + status.nsfw = isNsfw(status) } // Set deleted flag -- cgit v1.2.3-70-g09d2