forked from AkkomaGang/akkoma-fe
Merge branch 'streaming' into 'develop'
Streaming and Backend Interactor service overhaul, removed the need for copypasting See merge request pleroma/pleroma-fe!1012
This commit is contained in:
commit
b8f4b18ae5
22 changed files with 343 additions and 298 deletions
|
@ -7,11 +7,11 @@ const FollowRequestCard = {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
approveUser () {
|
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)
|
this.$store.dispatch('removeFollowRequest', this.user)
|
||||||
},
|
},
|
||||||
denyUser () {
|
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)
|
this.$store.dispatch('removeFollowRequest', this.user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,12 +45,12 @@ const ModerationTools = {
|
||||||
toggleTag (tag) {
|
toggleTag (tag) {
|
||||||
const store = this.$store
|
const store = this.$store
|
||||||
if (this.tagsSet.has(tag)) {
|
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 }
|
if (!response.ok) { return }
|
||||||
store.commit('untagUser', { user: this.user, tag })
|
store.commit('untagUser', { user: this.user, tag })
|
||||||
})
|
})
|
||||||
} else {
|
} 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 }
|
if (!response.ok) { return }
|
||||||
store.commit('tagUser', { user: this.user, tag })
|
store.commit('tagUser', { user: this.user, tag })
|
||||||
})
|
})
|
||||||
|
@ -59,19 +59,19 @@ const ModerationTools = {
|
||||||
toggleRight (right) {
|
toggleRight (right) {
|
||||||
const store = this.$store
|
const store = this.$store
|
||||||
if (this.user.rights[right]) {
|
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 }
|
if (!response.ok) { return }
|
||||||
store.commit('updateRight', { user: this.user, right: right, value: false })
|
store.commit('updateRight', { user: this.user, right, value: false })
|
||||||
})
|
})
|
||||||
} else {
|
} 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 }
|
if (!response.ok) { return }
|
||||||
store.commit('updateRight', { user: this.user, right: right, value: true })
|
store.commit('updateRight', { user: this.user, right, value: true })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleActivationStatus () {
|
toggleActivationStatus () {
|
||||||
this.$store.dispatch('toggleActivationStatus', this.user)
|
this.$store.dispatch('toggleActivationStatus', { user: this.user })
|
||||||
},
|
},
|
||||||
deleteUserDialog (show) {
|
deleteUserDialog (show) {
|
||||||
this.showDeleteUserDialog = show
|
this.showDeleteUserDialog = show
|
||||||
|
@ -80,7 +80,7 @@ const ModerationTools = {
|
||||||
const store = this.$store
|
const store = this.$store
|
||||||
const user = this.user
|
const user = this.user
|
||||||
const { id, name } = user
|
const { id, name } = user
|
||||||
store.state.api.backendInteractor.deleteUser(user)
|
store.state.api.backendInteractor.deleteUser({ user })
|
||||||
.then(e => {
|
.then(e => {
|
||||||
this.$store.dispatch('markStatusesAsDeleted', status => user.id === status.user.id)
|
this.$store.dispatch('markStatusesAsDeleted', status => user.id === status.user.id)
|
||||||
const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile'
|
const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile'
|
||||||
|
|
|
@ -47,6 +47,11 @@ const Notifications = {
|
||||||
components: {
|
components: {
|
||||||
Notification
|
Notification
|
||||||
},
|
},
|
||||||
|
created () {
|
||||||
|
const { dispatch } = this.$store
|
||||||
|
|
||||||
|
dispatch('fetchAndUpdateNotifications')
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
unseenCount (count) {
|
unseenCount (count) {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ const PublicAndExternalTimeline = {
|
||||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' })
|
this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' })
|
||||||
},
|
},
|
||||||
destroyed () {
|
destroyed () {
|
||||||
this.$store.dispatch('stopFetching', 'publicAndExternal')
|
this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ const PublicTimeline = {
|
||||||
this.$store.dispatch('startFetchingTimeline', { timeline: 'public' })
|
this.$store.dispatch('startFetchingTimeline', { timeline: 'public' })
|
||||||
},
|
},
|
||||||
destroyed () {
|
destroyed () {
|
||||||
this.$store.dispatch('stopFetching', 'public')
|
this.$store.dispatch('stopFetchingTimeline', 'public')
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ const settings = {
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
|
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
|
||||||
// Special cases (need to transform values)
|
// Special cases (need to transform values or perform actions first)
|
||||||
muteWordsString: {
|
muteWordsString: {
|
||||||
get () { return this.$store.getters.mergedConfig.muteWords.join('\n') },
|
get () { return this.$store.getters.mergedConfig.muteWords.join('\n') },
|
||||||
set (value) {
|
set (value) {
|
||||||
|
@ -93,6 +93,22 @@ const settings = {
|
||||||
value: filter(value.split('\n'), (word) => trim(word).length > 0)
|
value: filter(value.split('\n'), (word) => trim(word).length > 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
useStreamingApi: {
|
||||||
|
get () { return this.$store.getters.mergedConfig.useStreamingApi },
|
||||||
|
set (value) {
|
||||||
|
const promise = value
|
||||||
|
? this.$store.dispatch('enableMastoSockets')
|
||||||
|
: this.$store.dispatch('disableMastoSockets')
|
||||||
|
|
||||||
|
promise.then(() => {
|
||||||
|
this.$store.dispatch('setOption', { name: 'useStreamingApi', value })
|
||||||
|
}).catch((e) => {
|
||||||
|
console.error('Failed starting MastoAPI Streaming socket', e)
|
||||||
|
this.$store.dispatch('disableMastoSockets')
|
||||||
|
this.$store.dispatch('setOption', { name: 'useStreamingApi', value: false })
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Updating nested properties
|
// Updating nested properties
|
||||||
|
|
|
@ -73,6 +73,15 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<Checkbox v-model="useStreamingApi">
|
||||||
|
{{ $t('settings.useStreamingApi') }}
|
||||||
|
<br/>
|
||||||
|
<small>
|
||||||
|
{{ $t('settings.useStreamingApiWarning') }}
|
||||||
|
</small>
|
||||||
|
</Checkbox>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Checkbox v-model="autoLoad">
|
<Checkbox v-model="autoLoad">
|
||||||
{{ $t('settings.autoload') }}
|
{{ $t('settings.autoload') }}
|
||||||
|
|
|
@ -19,7 +19,7 @@ const TagTimeline = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroyed () {
|
destroyed () {
|
||||||
this.$store.dispatch('stopFetching', 'tag')
|
this.$store.dispatch('stopFetchingTimeline', 'tag')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,9 +112,9 @@ const UserProfile = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
stopFetching () {
|
stopFetching () {
|
||||||
this.$store.dispatch('stopFetching', 'user')
|
this.$store.dispatch('stopFetchingTimeline', 'user')
|
||||||
this.$store.dispatch('stopFetching', 'favorites')
|
this.$store.dispatch('stopFetchingTimeline', 'favorites')
|
||||||
this.$store.dispatch('stopFetching', 'media')
|
this.$store.dispatch('stopFetchingTimeline', 'media')
|
||||||
},
|
},
|
||||||
switchUser (userNameOrId) {
|
switchUser (userNameOrId) {
|
||||||
this.stopFetching()
|
this.stopFetching()
|
||||||
|
|
|
@ -64,7 +64,7 @@ const UserReportingModal = {
|
||||||
forward: this.forward,
|
forward: this.forward,
|
||||||
statusIds: this.statusIdsToReport
|
statusIds: this.statusIdsToReport
|
||||||
}
|
}
|
||||||
this.$store.state.api.backendInteractor.reportUser(params)
|
this.$store.state.api.backendInteractor.reportUser({ ...params })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.processing = false
|
this.processing = false
|
||||||
this.resetState()
|
this.resetState()
|
||||||
|
|
|
@ -242,7 +242,7 @@ const UserSettings = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
importFollows (file) {
|
importFollows (file) {
|
||||||
return this.$store.state.api.backendInteractor.importFollows(file)
|
return this.$store.state.api.backendInteractor.importFollows({ file })
|
||||||
.then((status) => {
|
.then((status) => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
throw new Error('failed')
|
throw new Error('failed')
|
||||||
|
@ -250,7 +250,7 @@ const UserSettings = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
importBlocks (file) {
|
importBlocks (file) {
|
||||||
return this.$store.state.api.backendInteractor.importBlocks(file)
|
return this.$store.state.api.backendInteractor.importBlocks({ file })
|
||||||
.then((status) => {
|
.then((status) => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
throw new Error('failed')
|
throw new Error('failed')
|
||||||
|
@ -297,7 +297,7 @@ const UserSettings = {
|
||||||
newPassword: this.changePasswordInputs[1],
|
newPassword: this.changePasswordInputs[1],
|
||||||
newPasswordConfirmation: this.changePasswordInputs[2]
|
newPasswordConfirmation: this.changePasswordInputs[2]
|
||||||
}
|
}
|
||||||
this.$store.state.api.backendInteractor.changePassword(params)
|
this.$store.state.api.backendInteractor.changePassword({ params })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 'success') {
|
if (res.status === 'success') {
|
||||||
this.changedPassword = true
|
this.changedPassword = true
|
||||||
|
@ -314,7 +314,7 @@ const UserSettings = {
|
||||||
email: this.newEmail,
|
email: this.newEmail,
|
||||||
password: this.changeEmailPassword
|
password: this.changeEmailPassword
|
||||||
}
|
}
|
||||||
this.$store.state.api.backendInteractor.changeEmail(params)
|
this.$store.state.api.backendInteractor.changeEmail({ params })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 'success') {
|
if (res.status === 'success') {
|
||||||
this.changedEmail = true
|
this.changedEmail = true
|
||||||
|
|
|
@ -358,6 +358,8 @@
|
||||||
"post_status_content_type": "Post status content type",
|
"post_status_content_type": "Post status content type",
|
||||||
"stop_gifs": "Play-on-hover GIFs",
|
"stop_gifs": "Play-on-hover GIFs",
|
||||||
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
|
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
|
||||||
|
"useStreamingApi": "Receive posts and notifications real-time",
|
||||||
|
"useStreamingApiWarning": "(Not recommended, experimental, known to skip posts)",
|
||||||
"text": "Text",
|
"text": "Text",
|
||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
"theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
|
"theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
|
||||||
|
|
|
@ -219,6 +219,8 @@
|
||||||
"subject_input_always_show": "Всегда показывать поле ввода темы",
|
"subject_input_always_show": "Всегда показывать поле ввода темы",
|
||||||
"stop_gifs": "Проигрывать GIF анимации только при наведении",
|
"stop_gifs": "Проигрывать GIF анимации только при наведении",
|
||||||
"streaming": "Включить автоматическую загрузку новых сообщений при прокрутке вверх",
|
"streaming": "Включить автоматическую загрузку новых сообщений при прокрутке вверх",
|
||||||
|
"useStreamingApi": "Получать сообщения и уведомления в реальном времени",
|
||||||
|
"useStreamingApiWarning": "(Не рекомендуется, экспериментально, сообщения могут пропадать)",
|
||||||
"text": "Текст",
|
"text": "Текст",
|
||||||
"theme": "Тема",
|
"theme": "Тема",
|
||||||
"theme_help": "Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.",
|
"theme_help": "Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.",
|
||||||
|
|
|
@ -6,6 +6,7 @@ const api = {
|
||||||
backendInteractor: backendInteractorService(),
|
backendInteractor: backendInteractorService(),
|
||||||
fetchers: {},
|
fetchers: {},
|
||||||
socket: null,
|
socket: null,
|
||||||
|
mastoUserSocket: null,
|
||||||
followRequests: []
|
followRequests: []
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
|
@ -15,7 +16,8 @@ const api = {
|
||||||
addFetcher (state, { fetcherName, fetcher }) {
|
addFetcher (state, { fetcherName, fetcher }) {
|
||||||
state.fetchers[fetcherName] = fetcher
|
state.fetchers[fetcherName] = fetcher
|
||||||
},
|
},
|
||||||
removeFetcher (state, { fetcherName }) {
|
removeFetcher (state, { fetcherName, fetcher }) {
|
||||||
|
window.clearInterval(fetcher)
|
||||||
delete state.fetchers[fetcherName]
|
delete state.fetchers[fetcherName]
|
||||||
},
|
},
|
||||||
setWsToken (state, token) {
|
setWsToken (state, token) {
|
||||||
|
@ -29,32 +31,134 @@ const api = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
startFetchingTimeline (store, { timeline = 'friends', tag = false, userId = false }) {
|
// Global MastoAPI socket control, in future should disable ALL sockets/(re)start relevant sockets
|
||||||
// Don't start fetching if we already are.
|
enableMastoSockets (store) {
|
||||||
|
const { state, dispatch } = store
|
||||||
|
if (state.mastoUserSocket) return
|
||||||
|
return dispatch('startMastoUserSocket')
|
||||||
|
},
|
||||||
|
disableMastoSockets (store) {
|
||||||
|
const { state, dispatch } = store
|
||||||
|
if (!state.mastoUserSocket) return
|
||||||
|
return dispatch('stopMastoUserSocket')
|
||||||
|
},
|
||||||
|
|
||||||
|
// MastoAPI 'User' sockets
|
||||||
|
startMastoUserSocket (store) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const { state, dispatch, rootState } = store
|
||||||
|
const timelineData = rootState.statuses.timelines.friends
|
||||||
|
state.mastoUserSocket = state.backendInteractor.startUserSocket({ store })
|
||||||
|
state.mastoUserSocket.addEventListener(
|
||||||
|
'message',
|
||||||
|
({ detail: message }) => {
|
||||||
|
if (!message) return // pings
|
||||||
|
if (message.event === 'notification') {
|
||||||
|
dispatch('addNewNotifications', {
|
||||||
|
notifications: [message.notification],
|
||||||
|
older: false
|
||||||
|
})
|
||||||
|
} else if (message.event === 'update') {
|
||||||
|
dispatch('addNewStatuses', {
|
||||||
|
statuses: [message.status],
|
||||||
|
userId: false,
|
||||||
|
showImmediately: timelineData.visibleStatuses.length === 0,
|
||||||
|
timeline: 'friends'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
state.mastoUserSocket.addEventListener('error', ({ detail: error }) => {
|
||||||
|
console.error('Error in MastoAPI websocket:', error)
|
||||||
|
})
|
||||||
|
state.mastoUserSocket.addEventListener('close', ({ detail: closeEvent }) => {
|
||||||
|
const ignoreCodes = new Set([
|
||||||
|
1000, // Normal (intended) closure
|
||||||
|
1001 // Going away
|
||||||
|
])
|
||||||
|
const { code } = 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')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
resolve()
|
||||||
|
} catch (e) {
|
||||||
|
reject(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
restartMastoUserSocket ({ dispatch }) {
|
||||||
|
// This basically starts MastoAPI user socket and stops conventional
|
||||||
|
// fetchers when connection reestablished
|
||||||
|
return dispatch('startMastoUserSocket').then(() => {
|
||||||
|
dispatch('stopFetchingTimeline', { timeline: 'friends' })
|
||||||
|
dispatch('stopFetchingNotifications')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
stopMastoUserSocket ({ state, dispatch }) {
|
||||||
|
dispatch('startFetchingTimeline', { timeline: 'friends' })
|
||||||
|
dispatch('startFetchingNotifications')
|
||||||
|
console.log(state.mastoUserSocket)
|
||||||
|
state.mastoUserSocket.close()
|
||||||
|
},
|
||||||
|
|
||||||
|
// Timelines
|
||||||
|
startFetchingTimeline (store, {
|
||||||
|
timeline = 'friends',
|
||||||
|
tag = false,
|
||||||
|
userId = false
|
||||||
|
}) {
|
||||||
if (store.state.fetchers[timeline]) return
|
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 })
|
store.commit('addFetcher', { fetcherName: timeline, fetcher })
|
||||||
},
|
},
|
||||||
startFetchingNotifications (store) {
|
stopFetchingTimeline (store, timeline) {
|
||||||
// Don't start fetching if we already are.
|
const fetcher = store.state.fetchers[timeline]
|
||||||
if (store.state.fetchers['notifications']) return
|
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 })
|
const fetcher = store.state.backendInteractor.startFetchingNotifications({ store })
|
||||||
store.commit('addFetcher', { fetcherName: 'notifications', fetcher })
|
store.commit('addFetcher', { fetcherName: 'notifications', fetcher })
|
||||||
},
|
},
|
||||||
startFetchingFollowRequest (store) {
|
stopFetchingNotifications (store) {
|
||||||
// Don't start fetching if we already are.
|
const fetcher = store.state.fetchers.notifications
|
||||||
if (store.state.fetchers['followRequest']) return
|
if (!fetcher) return
|
||||||
|
store.commit('removeFetcher', { fetcherName: 'notifications', fetcher })
|
||||||
|
},
|
||||||
|
fetchAndUpdateNotifications (store) {
|
||||||
|
store.state.backendInteractor.fetchAndUpdateNotifications({ store })
|
||||||
|
},
|
||||||
|
|
||||||
const fetcher = store.state.backendInteractor.startFetchingFollowRequest({ store })
|
// Follow requests
|
||||||
store.commit('addFetcher', { fetcherName: 'followRequest', fetcher })
|
startFetchingFollowRequests (store) {
|
||||||
|
if (store.state.fetchers['followRequests']) return
|
||||||
|
const fetcher = store.state.backendInteractor.startFetchingFollowRequests({ store })
|
||||||
|
store.commit('addFetcher', { fetcherName: 'followRequests', fetcher })
|
||||||
},
|
},
|
||||||
stopFetching (store, fetcherName) {
|
stopFetchingFollowRequests (store) {
|
||||||
const fetcher = store.state.fetchers[fetcherName]
|
const fetcher = store.state.fetchers.followRequests
|
||||||
window.clearInterval(fetcher)
|
if (!fetcher) return
|
||||||
store.commit('removeFetcher', { fetcherName })
|
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) {
|
setWsToken (store, token) {
|
||||||
store.commit('setWsToken', token)
|
store.commit('setWsToken', token)
|
||||||
},
|
},
|
||||||
|
@ -72,10 +176,6 @@ const api = {
|
||||||
disconnectFromSocket ({ commit, state }) {
|
disconnectFromSocket ({ commit, state }) {
|
||||||
state.socket && state.socket.disconnect()
|
state.socket && state.socket.disconnect()
|
||||||
commit('setSocket', null)
|
commit('setSocket', null)
|
||||||
},
|
|
||||||
removeFollowRequest (store, request) {
|
|
||||||
let requests = store.state.followRequests.filter((it) => it !== request)
|
|
||||||
store.commit('setFollowRequests', requests)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ export const defaultState = {
|
||||||
highlight: {},
|
highlight: {},
|
||||||
interfaceLanguage: browserLocale,
|
interfaceLanguage: browserLocale,
|
||||||
hideScopeNotice: false,
|
hideScopeNotice: false,
|
||||||
|
useStreamingApi: false,
|
||||||
scopeCopy: undefined, // instance default
|
scopeCopy: undefined, // instance default
|
||||||
subjectLineBehavior: undefined, // instance default
|
subjectLineBehavior: undefined, // instance default
|
||||||
alwaysShowSubjectInput: undefined, // instance default
|
alwaysShowSubjectInput: undefined, // instance default
|
||||||
|
|
|
@ -9,7 +9,7 @@ const oauthTokens = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
revokeToken ({ rootState, commit, state }, id) {
|
revokeToken ({ rootState, commit, state }, id) {
|
||||||
rootState.api.backendInteractor.revokeOAuthToken(id).then((response) => {
|
rootState.api.backendInteractor.revokeOAuthToken({ id }).then((response) => {
|
||||||
if (response.status === 201) {
|
if (response.status === 201) {
|
||||||
commit('swapTokens', state.tokens.filter(token => token.id !== id))
|
commit('swapTokens', state.tokens.filter(token => token.id !== id))
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ const polls = {
|
||||||
commit('mergeOrAddPoll', poll)
|
commit('mergeOrAddPoll', poll)
|
||||||
},
|
},
|
||||||
updateTrackedPoll ({ rootState, dispatch, commit }, pollId) {
|
updateTrackedPoll ({ rootState, dispatch, commit }, pollId) {
|
||||||
rootState.api.backendInteractor.fetchPoll(pollId).then(poll => {
|
rootState.api.backendInteractor.fetchPoll({ pollId }).then(poll => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (rootState.polls.trackedPolls[pollId]) {
|
if (rootState.polls.trackedPolls[pollId]) {
|
||||||
dispatch('updateTrackedPoll', pollId)
|
dispatch('updateTrackedPoll', pollId)
|
||||||
|
@ -59,7 +59,7 @@ const polls = {
|
||||||
commit('untrackPoll', pollId)
|
commit('untrackPoll', pollId)
|
||||||
},
|
},
|
||||||
votePoll ({ rootState, commit }, { id, pollId, choices }) {
|
votePoll ({ rootState, commit }, { id, pollId, choices }) {
|
||||||
return rootState.api.backendInteractor.vote(pollId, choices).then(poll => {
|
return rootState.api.backendInteractor.vote({ pollId, choices }).then(poll => {
|
||||||
commit('mergeOrAddPoll', poll)
|
commit('mergeOrAddPoll', poll)
|
||||||
return poll
|
return poll
|
||||||
})
|
})
|
||||||
|
|
|
@ -558,45 +558,45 @@ const statuses = {
|
||||||
favorite ({ rootState, commit }, status) {
|
favorite ({ rootState, commit }, status) {
|
||||||
// Optimistic favoriting...
|
// Optimistic favoriting...
|
||||||
commit('setFavorited', { status, value: true })
|
commit('setFavorited', { status, value: true })
|
||||||
rootState.api.backendInteractor.favorite(status.id)
|
rootState.api.backendInteractor.favorite({ id: status.id })
|
||||||
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
unfavorite ({ rootState, commit }, status) {
|
unfavorite ({ rootState, commit }, status) {
|
||||||
// Optimistic unfavoriting...
|
// Optimistic unfavoriting...
|
||||||
commit('setFavorited', { status, value: false })
|
commit('setFavorited', { status, value: false })
|
||||||
rootState.api.backendInteractor.unfavorite(status.id)
|
rootState.api.backendInteractor.unfavorite({ id: status.id })
|
||||||
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
fetchPinnedStatuses ({ rootState, dispatch }, userId) {
|
fetchPinnedStatuses ({ rootState, dispatch }, userId) {
|
||||||
rootState.api.backendInteractor.fetchPinnedStatuses(userId)
|
rootState.api.backendInteractor.fetchPinnedStatuses({ id: userId })
|
||||||
.then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true, noIdUpdate: true }))
|
.then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true, noIdUpdate: true }))
|
||||||
},
|
},
|
||||||
pinStatus ({ rootState, dispatch }, statusId) {
|
pinStatus ({ rootState, dispatch }, statusId) {
|
||||||
return rootState.api.backendInteractor.pinOwnStatus(statusId)
|
return rootState.api.backendInteractor.pinOwnStatus({ id: statusId })
|
||||||
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
|
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
|
||||||
},
|
},
|
||||||
unpinStatus ({ rootState, dispatch }, statusId) {
|
unpinStatus ({ rootState, dispatch }, statusId) {
|
||||||
rootState.api.backendInteractor.unpinOwnStatus(statusId)
|
rootState.api.backendInteractor.unpinOwnStatus({ id: statusId })
|
||||||
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
|
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
|
||||||
},
|
},
|
||||||
muteConversation ({ rootState, commit }, statusId) {
|
muteConversation ({ rootState, commit }, statusId) {
|
||||||
return rootState.api.backendInteractor.muteConversation(statusId)
|
return rootState.api.backendInteractor.muteConversation({ id: statusId })
|
||||||
.then((status) => commit('setMutedStatus', status))
|
.then((status) => commit('setMutedStatus', status))
|
||||||
},
|
},
|
||||||
unmuteConversation ({ rootState, commit }, statusId) {
|
unmuteConversation ({ rootState, commit }, statusId) {
|
||||||
return rootState.api.backendInteractor.unmuteConversation(statusId)
|
return rootState.api.backendInteractor.unmuteConversation({ id: statusId })
|
||||||
.then((status) => commit('setMutedStatus', status))
|
.then((status) => commit('setMutedStatus', status))
|
||||||
},
|
},
|
||||||
retweet ({ rootState, commit }, status) {
|
retweet ({ rootState, commit }, status) {
|
||||||
// Optimistic retweeting...
|
// Optimistic retweeting...
|
||||||
commit('setRetweeted', { status, value: true })
|
commit('setRetweeted', { status, value: true })
|
||||||
rootState.api.backendInteractor.retweet(status.id)
|
rootState.api.backendInteractor.retweet({ id: status.id })
|
||||||
.then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser }))
|
.then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
unretweet ({ rootState, commit }, status) {
|
unretweet ({ rootState, commit }, status) {
|
||||||
// Optimistic unretweeting...
|
// Optimistic unretweeting...
|
||||||
commit('setRetweeted', { status, value: false })
|
commit('setRetweeted', { status, value: false })
|
||||||
rootState.api.backendInteractor.unretweet(status.id)
|
rootState.api.backendInteractor.unretweet({ id: status.id })
|
||||||
.then(status => commit('setRetweetedConfirm', { status, user: rootState.users.currentUser }))
|
.then(status => commit('setRetweetedConfirm', { status, user: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
queueFlush ({ rootState, commit }, { timeline, id }) {
|
queueFlush ({ rootState, commit }, { timeline, id }) {
|
||||||
|
@ -611,19 +611,19 @@ const statuses = {
|
||||||
},
|
},
|
||||||
fetchFavsAndRepeats ({ rootState, commit }, id) {
|
fetchFavsAndRepeats ({ rootState, commit }, id) {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
rootState.api.backendInteractor.fetchFavoritedByUsers(id),
|
rootState.api.backendInteractor.fetchFavoritedByUsers({ id }),
|
||||||
rootState.api.backendInteractor.fetchRebloggedByUsers(id)
|
rootState.api.backendInteractor.fetchRebloggedByUsers({ id })
|
||||||
]).then(([favoritedByUsers, rebloggedByUsers]) => {
|
]).then(([favoritedByUsers, rebloggedByUsers]) => {
|
||||||
commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser })
|
commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser })
|
||||||
commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })
|
commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchFavs ({ rootState, commit }, id) {
|
fetchFavs ({ rootState, commit }, id) {
|
||||||
rootState.api.backendInteractor.fetchFavoritedByUsers(id)
|
rootState.api.backendInteractor.fetchFavoritedByUsers({ id })
|
||||||
.then(favoritedByUsers => commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser }))
|
.then(favoritedByUsers => commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
fetchRepeats ({ rootState, commit }, id) {
|
fetchRepeats ({ rootState, commit }, id) {
|
||||||
rootState.api.backendInteractor.fetchRebloggedByUsers(id)
|
rootState.api.backendInteractor.fetchRebloggedByUsers({ id })
|
||||||
.then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser }))
|
.then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser }))
|
||||||
},
|
},
|
||||||
search (store, { q, resolve, limit, offset, following }) {
|
search (store, { q, resolve, limit, offset, following }) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ const getNotificationPermission = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockUser = (store, id) => {
|
const blockUser = (store, id) => {
|
||||||
return store.rootState.api.backendInteractor.blockUser(id)
|
return store.rootState.api.backendInteractor.blockUser({ id })
|
||||||
.then((relationship) => {
|
.then((relationship) => {
|
||||||
store.commit('updateUserRelationship', [relationship])
|
store.commit('updateUserRelationship', [relationship])
|
||||||
store.commit('addBlockId', id)
|
store.commit('addBlockId', id)
|
||||||
|
@ -43,12 +43,12 @@ const blockUser = (store, id) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const unblockUser = (store, id) => {
|
const unblockUser = (store, id) => {
|
||||||
return store.rootState.api.backendInteractor.unblockUser(id)
|
return store.rootState.api.backendInteractor.unblockUser({ id })
|
||||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||||
}
|
}
|
||||||
|
|
||||||
const muteUser = (store, id) => {
|
const muteUser = (store, id) => {
|
||||||
return store.rootState.api.backendInteractor.muteUser(id)
|
return store.rootState.api.backendInteractor.muteUser({ id })
|
||||||
.then((relationship) => {
|
.then((relationship) => {
|
||||||
store.commit('updateUserRelationship', [relationship])
|
store.commit('updateUserRelationship', [relationship])
|
||||||
store.commit('addMuteId', id)
|
store.commit('addMuteId', id)
|
||||||
|
@ -56,7 +56,7 @@ const muteUser = (store, id) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const unmuteUser = (store, id) => {
|
const unmuteUser = (store, id) => {
|
||||||
return store.rootState.api.backendInteractor.unmuteUser(id)
|
return store.rootState.api.backendInteractor.unmuteUser({ id })
|
||||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,11 +324,11 @@ const users = {
|
||||||
commit('clearFollowers', userId)
|
commit('clearFollowers', userId)
|
||||||
},
|
},
|
||||||
subscribeUser ({ rootState, commit }, id) {
|
subscribeUser ({ rootState, commit }, id) {
|
||||||
return rootState.api.backendInteractor.subscribeUser(id)
|
return rootState.api.backendInteractor.subscribeUser({ id })
|
||||||
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
||||||
},
|
},
|
||||||
unsubscribeUser ({ rootState, commit }, id) {
|
unsubscribeUser ({ rootState, commit }, id) {
|
||||||
return rootState.api.backendInteractor.unsubscribeUser(id)
|
return rootState.api.backendInteractor.unsubscribeUser({ id })
|
||||||
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
||||||
},
|
},
|
||||||
toggleActivationStatus ({ rootState, commit }, user) {
|
toggleActivationStatus ({ rootState, commit }, user) {
|
||||||
|
@ -387,7 +387,7 @@ const users = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
searchUsers (store, query) {
|
searchUsers (store, query) {
|
||||||
return store.rootState.api.backendInteractor.searchUsers(query)
|
return store.rootState.api.backendInteractor.searchUsers({ query })
|
||||||
.then((users) => {
|
.then((users) => {
|
||||||
store.commit('addNewUsers', users)
|
store.commit('addNewUsers', users)
|
||||||
return users
|
return users
|
||||||
|
@ -399,7 +399,7 @@ const users = {
|
||||||
let rootState = store.rootState
|
let rootState = store.rootState
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let data = await rootState.api.backendInteractor.register(userInfo)
|
let data = await rootState.api.backendInteractor.register({ ...userInfo })
|
||||||
store.commit('signUpSuccess')
|
store.commit('signUpSuccess')
|
||||||
store.commit('setToken', data.access_token)
|
store.commit('setToken', data.access_token)
|
||||||
store.dispatch('loginUser', data.access_token)
|
store.dispatch('loginUser', data.access_token)
|
||||||
|
@ -436,10 +436,10 @@ const users = {
|
||||||
store.commit('clearCurrentUser')
|
store.commit('clearCurrentUser')
|
||||||
store.dispatch('disconnectFromSocket')
|
store.dispatch('disconnectFromSocket')
|
||||||
store.commit('clearToken')
|
store.commit('clearToken')
|
||||||
store.dispatch('stopFetching', 'friends')
|
store.dispatch('stopFetchingTimeline', 'friends')
|
||||||
store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
|
store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
|
||||||
store.dispatch('stopFetching', 'notifications')
|
store.dispatch('stopFetchingNotifications')
|
||||||
store.dispatch('stopFetching', 'followRequest')
|
store.dispatch('stopFetchingFollowRequests')
|
||||||
store.commit('clearNotifications')
|
store.commit('clearNotifications')
|
||||||
store.commit('resetStatuses')
|
store.commit('resetStatuses')
|
||||||
})
|
})
|
||||||
|
@ -474,11 +474,24 @@ const users = {
|
||||||
store.dispatch('initializeSocket')
|
store.dispatch('initializeSocket')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const startPolling = () => {
|
||||||
// Start getting fresh posts.
|
// Start getting fresh posts.
|
||||||
store.dispatch('startFetchingTimeline', { timeline: 'friends' })
|
store.dispatch('startFetchingTimeline', { timeline: 'friends' })
|
||||||
|
|
||||||
// Start fetching notifications
|
// Start fetching notifications
|
||||||
store.dispatch('startFetchingNotifications')
|
store.dispatch('startFetchingNotifications')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.getters.mergedConfig.useStreamingApi) {
|
||||||
|
store.dispatch('enableMastoSockets').catch((error) => {
|
||||||
|
console.error('Failed initializing MastoAPI Streaming socket', error)
|
||||||
|
startPolling()
|
||||||
|
}).then(() => {
|
||||||
|
setTimeout(() => store.dispatch('setNotificationsSilence', false), 10000)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
startPolling()
|
||||||
|
}
|
||||||
|
|
||||||
// Get user mutes
|
// Get user mutes
|
||||||
store.dispatch('fetchMutes')
|
store.dispatch('fetchMutes')
|
||||||
|
|
|
@ -72,6 +72,7 @@ const MASTODON_MUTE_CONVERSATION = id => `/api/v1/statuses/${id}/mute`
|
||||||
const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
|
const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
|
||||||
const MASTODON_SEARCH_2 = `/api/v2/search`
|
const MASTODON_SEARCH_2 = `/api/v2/search`
|
||||||
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
|
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
|
||||||
|
const MASTODON_STREAMING = '/api/v1/streaming'
|
||||||
|
|
||||||
const oldfetch = window.fetch
|
const oldfetch = window.fetch
|
||||||
|
|
||||||
|
@ -451,7 +452,7 @@ const deleteRight = ({ right, credentials, ...user }) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const activateUser = ({ credentials, screen_name: nickname }) => {
|
const activateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: ACTIVATE_USER_URL,
|
url: ACTIVATE_USER_URL,
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
|
@ -462,7 +463,7 @@ const activateUser = ({ credentials, screen_name: nickname }) => {
|
||||||
}).then(response => get(response, 'users.0'))
|
}).then(response => get(response, 'users.0'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const deactivateUser = ({ credentials, screen_name: nickname }) => {
|
const deactivateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: DEACTIVATE_USER_URL,
|
url: DEACTIVATE_USER_URL,
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
|
@ -947,6 +948,99 @@ const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => {
|
||||||
|
return Object.entries({
|
||||||
|
...(credentials
|
||||||
|
? { access_token: credentials }
|
||||||
|
: {}
|
||||||
|
),
|
||||||
|
stream,
|
||||||
|
...args
|
||||||
|
}).reduce((acc, [key, val]) => {
|
||||||
|
return acc + `${key}=${val}&`
|
||||||
|
}, MASTODON_STREAMING + '?')
|
||||||
|
}
|
||||||
|
|
||||||
|
const MASTODON_STREAMING_EVENTS = new Set([
|
||||||
|
'update',
|
||||||
|
'notification',
|
||||||
|
'delete',
|
||||||
|
'filters_changed'
|
||||||
|
])
|
||||||
|
|
||||||
|
// A thin wrapper around WebSocket API that allows adding a pre-processor to it
|
||||||
|
// Uses EventTarget and a CustomEvent to proxy events
|
||||||
|
export const ProcessedWS = ({
|
||||||
|
url,
|
||||||
|
preprocessor = handleMastoWS,
|
||||||
|
id = 'Unknown'
|
||||||
|
}) => {
|
||||||
|
const eventTarget = new EventTarget()
|
||||||
|
const socket = new WebSocket(url)
|
||||||
|
if (!socket) throw new Error(`Failed to create socket ${id}`)
|
||||||
|
const proxy = (original, eventName, processor = a => a) => {
|
||||||
|
original.addEventListener(eventName, (eventData) => {
|
||||||
|
eventTarget.dispatchEvent(new CustomEvent(
|
||||||
|
eventName,
|
||||||
|
{ detail: processor(eventData) }
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
socket.addEventListener('open', (wsEvent) => {
|
||||||
|
console.debug(`[WS][${id}] Socket connected`, wsEvent)
|
||||||
|
})
|
||||||
|
socket.addEventListener('error', (wsEvent) => {
|
||||||
|
console.debug(`[WS][${id}] Socket errored`, wsEvent)
|
||||||
|
})
|
||||||
|
socket.addEventListener('close', (wsEvent) => {
|
||||||
|
console.debug(
|
||||||
|
`[WS][${id}] Socket disconnected with code ${wsEvent.code}`,
|
||||||
|
wsEvent
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// Commented code reason: very spammy, uncomment to enable message debug logging
|
||||||
|
/*
|
||||||
|
socket.addEventListener('message', (wsEvent) => {
|
||||||
|
console.debug(
|
||||||
|
`[WS][${id}] Message received`,
|
||||||
|
wsEvent
|
||||||
|
)
|
||||||
|
})
|
||||||
|
/**/
|
||||||
|
|
||||||
|
proxy(socket, 'open')
|
||||||
|
proxy(socket, 'close')
|
||||||
|
proxy(socket, 'message', preprocessor)
|
||||||
|
proxy(socket, 'error')
|
||||||
|
|
||||||
|
// 1000 = Normal Closure
|
||||||
|
eventTarget.close = () => { socket.close(1000, 'Shutting down socket') }
|
||||||
|
|
||||||
|
return eventTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
export const handleMastoWS = (wsEvent) => {
|
||||||
|
const { data } = wsEvent
|
||||||
|
if (!data) return
|
||||||
|
const parsedEvent = JSON.parse(data)
|
||||||
|
const { event, payload } = parsedEvent
|
||||||
|
if (MASTODON_STREAMING_EVENTS.has(event)) {
|
||||||
|
// MastoBE and PleromaBE both send payload for delete as a PLAIN string
|
||||||
|
if (event === 'delete') {
|
||||||
|
return { event, id: payload }
|
||||||
|
}
|
||||||
|
const data = payload ? JSON.parse(payload) : null
|
||||||
|
if (event === 'update') {
|
||||||
|
return { event, status: parseStatus(data) }
|
||||||
|
} else if (event === 'notification') {
|
||||||
|
return { event, notification: parseNotification(data) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('Unknown event', wsEvent)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const apiService = {
|
const apiService = {
|
||||||
verifyCredentials,
|
verifyCredentials,
|
||||||
fetchTimeline,
|
fetchTimeline,
|
||||||
|
|
|
@ -1,236 +1,39 @@
|
||||||
import apiService from '../api/api.service.js'
|
import apiService, { getMastodonSocketURI, ProcessedWS } from '../api/api.service.js'
|
||||||
import timelineFetcherService from '../timeline_fetcher/timeline_fetcher.service.js'
|
import timelineFetcherService from '../timeline_fetcher/timeline_fetcher.service.js'
|
||||||
import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js'
|
import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js'
|
||||||
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
|
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
|
||||||
|
|
||||||
const backendInteractorService = credentials => {
|
const backendInteractorService = credentials => ({
|
||||||
const fetchStatus = ({ id }) => {
|
startFetchingTimeline ({ timeline, store, userId = false, tag }) {
|
||||||
return apiService.fetchStatus({ id, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchConversation = ({ id }) => {
|
|
||||||
return apiService.fetchConversation({ id, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchFriends = ({ id, maxId, sinceId, limit }) => {
|
|
||||||
return apiService.fetchFriends({ id, maxId, sinceId, limit, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const exportFriends = ({ id }) => {
|
|
||||||
return apiService.exportFriends({ id, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchFollowers = ({ id, maxId, sinceId, limit }) => {
|
|
||||||
return apiService.fetchFollowers({ id, maxId, sinceId, limit, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchUser = ({ id }) => {
|
|
||||||
return apiService.fetchUser({ id, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchUserRelationship = ({ id }) => {
|
|
||||||
return apiService.fetchUserRelationship({ id, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const followUser = ({ id, reblogs }) => {
|
|
||||||
return apiService.followUser({ credentials, id, reblogs })
|
|
||||||
}
|
|
||||||
|
|
||||||
const unfollowUser = (id) => {
|
|
||||||
return apiService.unfollowUser({ credentials, id })
|
|
||||||
}
|
|
||||||
|
|
||||||
const blockUser = (id) => {
|
|
||||||
return apiService.blockUser({ credentials, id })
|
|
||||||
}
|
|
||||||
|
|
||||||
const unblockUser = (id) => {
|
|
||||||
return apiService.unblockUser({ credentials, id })
|
|
||||||
}
|
|
||||||
|
|
||||||
const approveUser = (id) => {
|
|
||||||
return apiService.approveUser({ credentials, id })
|
|
||||||
}
|
|
||||||
|
|
||||||
const denyUser = (id) => {
|
|
||||||
return apiService.denyUser({ credentials, id })
|
|
||||||
}
|
|
||||||
|
|
||||||
const startFetchingTimeline = ({ timeline, store, userId = false, tag }) => {
|
|
||||||
return timelineFetcherService.startFetching({ timeline, store, credentials, userId, tag })
|
return timelineFetcherService.startFetching({ timeline, store, credentials, userId, tag })
|
||||||
}
|
},
|
||||||
|
|
||||||
const startFetchingNotifications = ({ store }) => {
|
startFetchingNotifications ({ store }) {
|
||||||
return notificationsFetcher.startFetching({ store, credentials })
|
return notificationsFetcher.startFetching({ store, credentials })
|
||||||
}
|
},
|
||||||
|
|
||||||
const startFetchingFollowRequest = ({ store }) => {
|
fetchAndUpdateNotifications ({ store }) {
|
||||||
|
return notificationsFetcher.fetchAndUpdate({ store, credentials })
|
||||||
|
},
|
||||||
|
|
||||||
|
startFetchingFollowRequest ({ store }) {
|
||||||
return followRequestFetcher.startFetching({ store, credentials })
|
return followRequestFetcher.startFetching({ store, credentials })
|
||||||
|
},
|
||||||
|
|
||||||
|
startUserSocket ({ store }) {
|
||||||
|
const serv = store.rootState.instance.server.replace('http', 'ws')
|
||||||
|
const url = serv + getMastodonSocketURI({ credentials, stream: 'user' })
|
||||||
|
return ProcessedWS({ url, id: 'User' })
|
||||||
|
},
|
||||||
|
|
||||||
|
...Object.entries(apiService).reduce((acc, [key, func]) => {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[key]: (args) => func({ credentials, ...args })
|
||||||
}
|
}
|
||||||
|
}, {}),
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
verifyCredentials: apiService.verifyCredentials
|
||||||
const tagUser = ({ screen_name }, tag) => {
|
})
|
||||||
return apiService.tagUser({ screen_name, tag, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
const untagUser = ({ screen_name }, tag) => {
|
|
||||||
return apiService.untagUser({ screen_name, tag, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
const addRight = ({ screen_name }, right) => {
|
|
||||||
return apiService.addRight({ screen_name, right, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
const deleteRight = ({ screen_name }, right) => {
|
|
||||||
return apiService.deleteRight({ screen_name, right, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
const activateUser = ({ screen_name }) => {
|
|
||||||
return apiService.activateUser({ screen_name, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
const deactivateUser = ({ screen_name }) => {
|
|
||||||
return apiService.deactivateUser({ screen_name, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
const deleteUser = ({ screen_name }) => {
|
|
||||||
return apiService.deleteUser({ screen_name, credentials })
|
|
||||||
}
|
|
||||||
|
|
||||||
const vote = (pollId, choices) => {
|
|
||||||
return apiService.vote({ credentials, pollId, choices })
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchPoll = (pollId) => {
|
|
||||||
return apiService.fetchPoll({ credentials, pollId })
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateNotificationSettings = ({ settings }) => {
|
|
||||||
return apiService.updateNotificationSettings({ credentials, settings })
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchMutes = () => apiService.fetchMutes({ credentials })
|
|
||||||
const muteUser = (id) => apiService.muteUser({ credentials, id })
|
|
||||||
const unmuteUser = (id) => apiService.unmuteUser({ credentials, id })
|
|
||||||
const subscribeUser = (id) => apiService.subscribeUser({ credentials, id })
|
|
||||||
const unsubscribeUser = (id) => apiService.unsubscribeUser({ credentials, id })
|
|
||||||
const fetchBlocks = () => apiService.fetchBlocks({ credentials })
|
|
||||||
const fetchOAuthTokens = () => apiService.fetchOAuthTokens({ credentials })
|
|
||||||
const revokeOAuthToken = (id) => apiService.revokeOAuthToken({ id, credentials })
|
|
||||||
const fetchPinnedStatuses = (id) => apiService.fetchPinnedStatuses({ credentials, id })
|
|
||||||
const pinOwnStatus = (id) => apiService.pinOwnStatus({ credentials, id })
|
|
||||||
const unpinOwnStatus = (id) => apiService.unpinOwnStatus({ credentials, id })
|
|
||||||
const muteConversation = (id) => apiService.muteConversation({ credentials, id })
|
|
||||||
const unmuteConversation = (id) => apiService.unmuteConversation({ credentials, id })
|
|
||||||
|
|
||||||
const getCaptcha = () => apiService.getCaptcha()
|
|
||||||
const register = (params) => apiService.register({ credentials, params })
|
|
||||||
const updateAvatar = ({ avatar }) => apiService.updateAvatar({ credentials, avatar })
|
|
||||||
const updateBg = ({ background }) => apiService.updateBg({ credentials, background })
|
|
||||||
const updateBanner = ({ banner }) => apiService.updateBanner({ credentials, banner })
|
|
||||||
const updateProfile = ({ params }) => apiService.updateProfile({ credentials, params })
|
|
||||||
|
|
||||||
const importBlocks = (file) => apiService.importBlocks({ file, credentials })
|
|
||||||
const importFollows = (file) => apiService.importFollows({ file, credentials })
|
|
||||||
|
|
||||||
const deleteAccount = ({ password }) => apiService.deleteAccount({ credentials, password })
|
|
||||||
const changeEmail = ({ email, password }) => apiService.changeEmail({ credentials, email, password })
|
|
||||||
const changePassword = ({ password, newPassword, newPasswordConfirmation }) =>
|
|
||||||
apiService.changePassword({ credentials, password, newPassword, newPasswordConfirmation })
|
|
||||||
|
|
||||||
const fetchSettingsMFA = () => apiService.settingsMFA({ credentials })
|
|
||||||
const generateMfaBackupCodes = () => apiService.generateMfaBackupCodes({ credentials })
|
|
||||||
const mfaSetupOTP = () => apiService.mfaSetupOTP({ credentials })
|
|
||||||
const mfaConfirmOTP = ({ password, token }) => apiService.mfaConfirmOTP({ credentials, password, token })
|
|
||||||
const mfaDisableOTP = ({ password }) => apiService.mfaDisableOTP({ credentials, password })
|
|
||||||
|
|
||||||
const fetchFavoritedByUsers = (id) => apiService.fetchFavoritedByUsers({ id })
|
|
||||||
const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({ id })
|
|
||||||
const reportUser = (params) => apiService.reportUser({ credentials, ...params })
|
|
||||||
|
|
||||||
const favorite = (id) => apiService.favorite({ id, credentials })
|
|
||||||
const unfavorite = (id) => apiService.unfavorite({ id, credentials })
|
|
||||||
const retweet = (id) => apiService.retweet({ id, credentials })
|
|
||||||
const unretweet = (id) => apiService.unretweet({ id, credentials })
|
|
||||||
const search2 = ({ q, resolve, limit, offset, following }) =>
|
|
||||||
apiService.search2({ credentials, q, resolve, limit, offset, following })
|
|
||||||
const searchUsers = (query) => apiService.searchUsers({ query, credentials })
|
|
||||||
|
|
||||||
const backendInteractorServiceInstance = {
|
|
||||||
fetchStatus,
|
|
||||||
fetchConversation,
|
|
||||||
fetchFriends,
|
|
||||||
exportFriends,
|
|
||||||
fetchFollowers,
|
|
||||||
followUser,
|
|
||||||
unfollowUser,
|
|
||||||
blockUser,
|
|
||||||
unblockUser,
|
|
||||||
fetchUser,
|
|
||||||
fetchUserRelationship,
|
|
||||||
verifyCredentials: apiService.verifyCredentials,
|
|
||||||
startFetchingTimeline,
|
|
||||||
startFetchingNotifications,
|
|
||||||
startFetchingFollowRequest,
|
|
||||||
fetchMutes,
|
|
||||||
muteUser,
|
|
||||||
unmuteUser,
|
|
||||||
subscribeUser,
|
|
||||||
unsubscribeUser,
|
|
||||||
fetchBlocks,
|
|
||||||
fetchOAuthTokens,
|
|
||||||
revokeOAuthToken,
|
|
||||||
fetchPinnedStatuses,
|
|
||||||
pinOwnStatus,
|
|
||||||
unpinOwnStatus,
|
|
||||||
muteConversation,
|
|
||||||
unmuteConversation,
|
|
||||||
tagUser,
|
|
||||||
untagUser,
|
|
||||||
addRight,
|
|
||||||
deleteRight,
|
|
||||||
deleteUser,
|
|
||||||
activateUser,
|
|
||||||
deactivateUser,
|
|
||||||
register,
|
|
||||||
getCaptcha,
|
|
||||||
updateAvatar,
|
|
||||||
updateBg,
|
|
||||||
updateBanner,
|
|
||||||
updateProfile,
|
|
||||||
importBlocks,
|
|
||||||
importFollows,
|
|
||||||
deleteAccount,
|
|
||||||
changeEmail,
|
|
||||||
changePassword,
|
|
||||||
fetchSettingsMFA,
|
|
||||||
generateMfaBackupCodes,
|
|
||||||
mfaSetupOTP,
|
|
||||||
mfaConfirmOTP,
|
|
||||||
mfaDisableOTP,
|
|
||||||
approveUser,
|
|
||||||
denyUser,
|
|
||||||
vote,
|
|
||||||
fetchPoll,
|
|
||||||
fetchFavoritedByUsers,
|
|
||||||
fetchRebloggedByUsers,
|
|
||||||
reportUser,
|
|
||||||
favorite,
|
|
||||||
unfavorite,
|
|
||||||
retweet,
|
|
||||||
unretweet,
|
|
||||||
updateNotificationSettings,
|
|
||||||
search2,
|
|
||||||
searchUsers
|
|
||||||
}
|
|
||||||
|
|
||||||
return backendInteractorServiceInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
export default backendInteractorService
|
export default backendInteractorService
|
||||||
|
|
|
@ -39,7 +39,7 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
export const requestUnfollow = (user, store) => new Promise((resolve, reject) => {
|
export const requestUnfollow = (user, store) => new Promise((resolve, reject) => {
|
||||||
store.state.api.backendInteractor.unfollowUser(user.id)
|
store.state.api.backendInteractor.unfollowUser({ id: user.id })
|
||||||
.then((updated) => {
|
.then((updated) => {
|
||||||
store.commit('updateUserRelationship', [updated])
|
store.commit('updateUserRelationship', [updated])
|
||||||
resolve({
|
resolve({
|
||||||
|
|
Loading…
Reference in a new issue