forked from mirrors/akkoma-fe
Merge branch '227-manage-blocks-mutes' into 'develop'
Transition to MastoAPI: Mute & Block and Add Mutes management tab See merge request pleroma/pleroma-fe!611
This commit is contained in:
commit
01d0531699
14 changed files with 128 additions and 91 deletions
|
@ -97,6 +97,7 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
|
|||
copyInstanceOption('showInstanceSpecificPanel')
|
||||
copyInstanceOption('scopeOptionsEnabled')
|
||||
copyInstanceOption('formattingOptionsEnabled')
|
||||
copyInstanceOption('hideMutedPosts')
|
||||
copyInstanceOption('collapseMessageWithSubject')
|
||||
copyInstanceOption('loginMethod')
|
||||
copyInstanceOption('scopeCopy')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<basic-user-card :user="user">
|
||||
<template slot="secondary-area">
|
||||
<div class="mute-card-content-container">
|
||||
<button class="btn btn-default" @click="unmuteUser" :disabled="progress" v-if="muted">
|
||||
<template v-if="progress">
|
||||
{{ $t('user_card.unmute_progress') }}
|
||||
|
@ -17,8 +17,18 @@
|
|||
{{ $t('user_card.mute') }}
|
||||
</template>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</basic-user-card>
|
||||
</template>
|
||||
|
||||
<script src="./mute_card.js"></script>
|
||||
<script src="./mute_card.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
.mute-card-content-container {
|
||||
margin-top: 0.5em;
|
||||
text-align: right;
|
||||
button {
|
||||
width: 10em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -47,6 +47,11 @@ const settings = {
|
|||
pauseOnUnfocusedLocal: user.pauseOnUnfocused,
|
||||
hoverPreviewLocal: user.hoverPreview,
|
||||
|
||||
hideMutedPostsLocal: typeof user.hideMutedPosts === 'undefined'
|
||||
? instance.hideMutedPosts
|
||||
: user.hideMutedPosts,
|
||||
hideMutedPostsDefault: this.$t('settings.values.' + instance.hideMutedPosts),
|
||||
|
||||
collapseMessageWithSubjectLocal: typeof user.collapseMessageWithSubject === 'undefined'
|
||||
? instance.collapseMessageWithSubject
|
||||
: user.collapseMessageWithSubject,
|
||||
|
@ -177,6 +182,9 @@ const settings = {
|
|||
value = filter(value.split('\n'), (word) => trim(word).length > 0)
|
||||
this.$store.dispatch('setOption', { name: 'muteWords', value })
|
||||
},
|
||||
hideMutedPostsLocal (value) {
|
||||
this.$store.dispatch('setOption', { name: 'hideMutedPosts', value })
|
||||
},
|
||||
collapseMessageWithSubjectLocal (value) {
|
||||
this.$store.dispatch('setOption', { name: 'collapseMessageWithSubject', value })
|
||||
},
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
<div class="setting-item">
|
||||
<h2>{{$t('nav.timeline')}}</h2>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<input type="checkbox" id="hideMutedPosts" v-model="hideMutedPostsLocal">
|
||||
<label for="hideMutedPosts">{{$t('settings.hide_muted_posts')}} {{$t('settings.instance_default', { value: hideMutedPostsDefault })}}</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="collapseMessageWithSubject" v-model="collapseMessageWithSubjectLocal">
|
||||
<label for="collapseMessageWithSubject">
|
||||
|
|
|
@ -121,24 +121,16 @@ export default {
|
|||
})
|
||||
},
|
||||
blockUser () {
|
||||
const store = this.$store
|
||||
store.state.api.backendInteractor.blockUser(this.user.id)
|
||||
.then((blockedUser) => {
|
||||
store.commit('addNewUsers', [blockedUser])
|
||||
store.commit('removeStatus', { timeline: 'friends', userId: this.user.id })
|
||||
store.commit('removeStatus', { timeline: 'public', userId: this.user.id })
|
||||
store.commit('removeStatus', { timeline: 'publicAndExternal', userId: this.user.id })
|
||||
})
|
||||
this.$store.dispatch('blockUser', this.user.id)
|
||||
},
|
||||
unblockUser () {
|
||||
const store = this.$store
|
||||
store.state.api.backendInteractor.unblockUser(this.user.id)
|
||||
.then((unblockedUser) => store.commit('addNewUsers', [unblockedUser]))
|
||||
this.$store.dispatch('unblockUser', this.user.id)
|
||||
},
|
||||
toggleMute () {
|
||||
const store = this.$store
|
||||
store.commit('setMuted', {user: this.user, muted: !this.user.muted})
|
||||
store.state.api.backendInteractor.setUserMute(this.user)
|
||||
muteUser () {
|
||||
this.$store.dispatch('muteUser', this.user.id)
|
||||
},
|
||||
unmuteUser () {
|
||||
this.$store.dispatch('unmuteUser', this.user.id)
|
||||
},
|
||||
setProfileView (v) {
|
||||
if (this.switcher) {
|
||||
|
|
|
@ -74,12 +74,12 @@
|
|||
</div>
|
||||
<div class='mute' v-if='isOtherUser && loggedIn'>
|
||||
<span v-if='user.muted'>
|
||||
<button @click="toggleMute" class="pressed">
|
||||
<button @click="unmuteUser" class="pressed">
|
||||
{{ $t('user_card.muted') }}
|
||||
</button>
|
||||
</span>
|
||||
<span v-if='!user.muted'>
|
||||
<button @click="toggleMute">
|
||||
<button @click="muteUser">
|
||||
{{ $t('user_card.mute') }}
|
||||
</button>
|
||||
</span>
|
||||
|
|
|
@ -192,6 +192,12 @@
|
|||
<template slot="empty">{{$t('settings.no_blocks')}}</template>
|
||||
</block-list>
|
||||
</div>
|
||||
|
||||
<div :label="$t('settings.mutes_tab')">
|
||||
<mute-list :refresh="true">
|
||||
<template slot="empty">{{$t('settings.no_mutes')}}</template>
|
||||
</mute-list>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -153,6 +153,7 @@
|
|||
"general": "General",
|
||||
"hide_attachments_in_convo": "Hide attachments in conversations",
|
||||
"hide_attachments_in_tl": "Hide attachments in timeline",
|
||||
"hide_muted_posts": "Hide posts of muted users",
|
||||
"max_thumbnails": "Maximum amount of thumbnails per post",
|
||||
"hide_isp": "Hide instance-specific panel",
|
||||
"preload_images": "Preload images",
|
||||
|
|
|
@ -5,6 +5,7 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0]
|
|||
|
||||
const defaultState = {
|
||||
colors: {},
|
||||
hideMutedPosts: undefined, // instance default
|
||||
collapseMessageWithSubject: undefined, // instance default
|
||||
hideAttachments: false,
|
||||
hideAttachmentsInConv: false,
|
||||
|
|
|
@ -18,6 +18,7 @@ const defaultState = {
|
|||
scopeOptionsEnabled: true,
|
||||
formattingOptionsEnabled: false,
|
||||
alwaysShowSubjectInput: true,
|
||||
hideMutedPosts: false,
|
||||
collapseMessageWithSubject: false,
|
||||
hidePostStats: false,
|
||||
hideUserStats: false,
|
||||
|
|
|
@ -102,10 +102,20 @@ export const mutations = {
|
|||
}
|
||||
})
|
||||
},
|
||||
saveBlocks (state, blockIds) {
|
||||
updateBlocks (state, blockedUsers) {
|
||||
// Reset statusnet_blocking of all fetched users
|
||||
each(state.users, (user) => { user.statusnet_blocking = false })
|
||||
each(blockedUsers, (user) => mergeOrAdd(state.users, state.usersObject, user))
|
||||
},
|
||||
saveBlockIds (state, blockIds) {
|
||||
state.currentUser.blockIds = blockIds
|
||||
},
|
||||
saveMutes (state, muteIds) {
|
||||
updateMutes (state, mutedUsers) {
|
||||
// Reset muted of all fetched users
|
||||
each(state.users, (user) => { user.muted = false })
|
||||
each(mutedUsers, (user) => mergeOrAdd(state.users, state.usersObject, user))
|
||||
},
|
||||
saveMuteIds (state, muteIds) {
|
||||
state.currentUser.muteIds = muteIds
|
||||
},
|
||||
setUserForStatus (state, status) {
|
||||
|
@ -172,34 +182,39 @@ const users = {
|
|||
fetchBlocks (store) {
|
||||
return store.rootState.api.backendInteractor.fetchBlocks()
|
||||
.then((blocks) => {
|
||||
store.commit('saveBlocks', map(blocks, 'id'))
|
||||
store.commit('addNewUsers', blocks)
|
||||
store.commit('saveBlockIds', map(blocks, 'id'))
|
||||
store.commit('updateBlocks', blocks)
|
||||
return blocks
|
||||
})
|
||||
},
|
||||
blockUser (store, id) {
|
||||
return store.rootState.api.backendInteractor.blockUser(id)
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
blockUser (store, userId) {
|
||||
return store.rootState.api.backendInteractor.blockUser(userId)
|
||||
.then((relationship) => {
|
||||
store.commit('updateUserRelationship', [relationship])
|
||||
store.commit('removeStatus', { timeline: 'friends', userId })
|
||||
store.commit('removeStatus', { timeline: 'public', userId })
|
||||
store.commit('removeStatus', { timeline: 'publicAndExternal', userId })
|
||||
})
|
||||
},
|
||||
unblockUser (store, id) {
|
||||
return store.rootState.api.backendInteractor.unblockUser(id)
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
},
|
||||
fetchMutes (store) {
|
||||
return store.rootState.api.backendInteractor.fetchMutes()
|
||||
.then((mutedUsers) => {
|
||||
each(mutedUsers, (user) => { user.muted = true })
|
||||
store.commit('addNewUsers', mutedUsers)
|
||||
store.commit('saveMutes', map(mutedUsers, 'id'))
|
||||
.then((mutes) => {
|
||||
store.commit('updateMutes', mutes)
|
||||
store.commit('saveMuteIds', map(mutes, 'id'))
|
||||
return mutes
|
||||
})
|
||||
},
|
||||
muteUser (store, id) {
|
||||
return store.state.api.backendInteractor.setUserMute({ id, muted: true })
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
return store.rootState.api.backendInteractor.muteUser(id)
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
},
|
||||
unmuteUser (store, id) {
|
||||
return store.state.api.backendInteractor.setUserMute({ id, muted: false })
|
||||
.then((user) => store.commit('addNewUsers', [user]))
|
||||
return store.rootState.api.backendInteractor.unmuteUser(id)
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
},
|
||||
addFriends ({ rootState, commit }, fetchBy) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
@ -18,10 +18,8 @@ const MENTIONS_URL = '/api/statuses/mentions.json'
|
|||
const DM_TIMELINE_URL = '/api/statuses/dm_timeline.json'
|
||||
const FOLLOWERS_URL = '/api/statuses/followers.json'
|
||||
const FRIENDS_URL = '/api/statuses/friends.json'
|
||||
const BLOCKS_URL = '/api/statuses/blocks.json'
|
||||
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 REGISTRATION_URL = '/api/account/register.json'
|
||||
const AVATAR_UPDATE_URL = '/api/qvitter/update_avatar.json'
|
||||
const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
|
||||
|
@ -30,8 +28,6 @@ const PROFILE_UPDATE_URL = '/api/account/update_profile.json'
|
|||
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
|
||||
const QVITTER_USER_NOTIFICATIONS_URL = '/api/qvitter/statuses/notifications.json'
|
||||
const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
|
||||
const BLOCKING_URL = '/api/blocks/create.json'
|
||||
const UNBLOCKING_URL = '/api/blocks/destroy.json'
|
||||
const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
|
||||
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
|
||||
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
||||
|
@ -44,6 +40,12 @@ const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
|
|||
const MASTODON_USER_URL = '/api/v1/accounts'
|
||||
const MASTODON_USER_RELATIONSHIPS_URL = '/api/v1/accounts/relationships'
|
||||
const MASTODON_USER_TIMELINE_URL = id => `/api/v1/accounts/${id}/statuses`
|
||||
const MASTODON_USER_BLOCKS_URL = '/api/v1/blocks/'
|
||||
const MASTODON_USER_MUTES_URL = '/api/v1/mutes/'
|
||||
const MASTODON_BLOCK_USER_URL = id => `/api/v1/accounts/${id}/block`
|
||||
const MASTODON_UNBLOCK_USER_URL = id => `/api/v1/accounts/${id}/unblock`
|
||||
const MASTODON_MUTE_USER_URL = id => `/api/v1/accounts/${id}/mute`
|
||||
const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
|
||||
|
||||
import { each, map } from 'lodash'
|
||||
import { parseStatus, parseUser, parseNotification } from '../entity_normalizer/entity_normalizer.service.js'
|
||||
|
@ -60,6 +62,19 @@ let fetch = (url, options) => {
|
|||
return oldfetch(fullUrl, options)
|
||||
}
|
||||
|
||||
const promisedRequest = (url, options) => {
|
||||
return fetch(url, options)
|
||||
.then((response) => {
|
||||
return new Promise((resolve, reject) => response.json()
|
||||
.then((json) => {
|
||||
if (!response.ok) {
|
||||
return reject(new StatusCodeError(response.status, json, { url, options }, response))
|
||||
}
|
||||
return resolve(json)
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
// Params
|
||||
// cropH
|
||||
// cropW
|
||||
|
@ -212,16 +227,14 @@ const unfollowUser = ({id, credentials}) => {
|
|||
}
|
||||
|
||||
const blockUser = ({id, credentials}) => {
|
||||
let url = `${BLOCKING_URL}?user_id=${id}`
|
||||
return fetch(url, {
|
||||
return fetch(MASTODON_BLOCK_USER_URL(id), {
|
||||
headers: authHeaders(credentials),
|
||||
method: 'POST'
|
||||
}).then((data) => data.json())
|
||||
}
|
||||
|
||||
const unblockUser = ({id, credentials}) => {
|
||||
let url = `${UNBLOCKING_URL}?user_id=${id}`
|
||||
return fetch(url, {
|
||||
return fetch(MASTODON_UNBLOCK_USER_URL(id), {
|
||||
headers: authHeaders(credentials),
|
||||
method: 'POST'
|
||||
}).then((data) => data.json())
|
||||
|
@ -245,16 +258,7 @@ const denyUser = ({id, credentials}) => {
|
|||
|
||||
const fetchUser = ({id, credentials}) => {
|
||||
let url = `${MASTODON_USER_URL}/${id}`
|
||||
return fetch(url, { headers: authHeaders(credentials) })
|
||||
.then((response) => {
|
||||
return new Promise((resolve, reject) => response.json()
|
||||
.then((json) => {
|
||||
if (!response.ok) {
|
||||
return reject(new StatusCodeError(response.status, json, { url }, response))
|
||||
}
|
||||
return resolve(json)
|
||||
}))
|
||||
})
|
||||
return promisedRequest(url, { headers: authHeaders(credentials) })
|
||||
.then((data) => parseUser(data))
|
||||
}
|
||||
|
||||
|
@ -338,23 +342,7 @@ const fetchStatus = ({id, credentials}) => {
|
|||
.then((data) => parseStatus(data))
|
||||
}
|
||||
|
||||
const setUserMute = ({id, credentials, muted = true}) => {
|
||||
const form = new FormData()
|
||||
|
||||
const muteInteger = muted ? 1 : 0
|
||||
|
||||
form.append('namespace', 'qvitter')
|
||||
form.append('data', muteInteger)
|
||||
form.append('topic', `mute:${id}`)
|
||||
|
||||
return fetch(QVITTER_USER_PREF_URL, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(credentials),
|
||||
body: form
|
||||
})
|
||||
}
|
||||
|
||||
const fetchTimeline = ({timeline, credentials, since = false, until = false, userId = false, tag = false}) => {
|
||||
const fetchTimeline = ({timeline, credentials, since = false, until = false, userId = false, tag = false, withMuted = false}) => {
|
||||
const timelineUrls = {
|
||||
public: PUBLIC_TIMELINE_URL,
|
||||
friends: FRIENDS_TIMELINE_URL,
|
||||
|
@ -390,6 +378,7 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
|
|||
}
|
||||
|
||||
params.push(['count', 20])
|
||||
params.push(['with_muted', withMuted])
|
||||
|
||||
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
|
||||
url += `?${queryString}`
|
||||
|
@ -538,24 +527,29 @@ const changePassword = ({credentials, password, newPassword, newPasswordConfirma
|
|||
}
|
||||
|
||||
const fetchMutes = ({credentials}) => {
|
||||
const url = '/api/qvitter/mutes.json'
|
||||
|
||||
return fetch(url, {
|
||||
headers: authHeaders(credentials)
|
||||
}).then((data) => data.json())
|
||||
return promisedRequest(MASTODON_USER_MUTES_URL, { headers: authHeaders(credentials) })
|
||||
.then((users) => users.map(parseUser))
|
||||
}
|
||||
|
||||
const fetchBlocks = ({page, credentials}) => {
|
||||
return fetch(BLOCKS_URL, {
|
||||
headers: authHeaders(credentials)
|
||||
}).then((data) => {
|
||||
if (data.ok) {
|
||||
return data.json()
|
||||
}
|
||||
throw new Error('Error fetching blocks', data)
|
||||
const muteUser = ({id, credentials}) => {
|
||||
return promisedRequest(MASTODON_MUTE_USER_URL(id), {
|
||||
headers: authHeaders(credentials),
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
||||
|
||||
const unmuteUser = ({id, credentials}) => {
|
||||
return promisedRequest(MASTODON_UNMUTE_USER_URL(id), {
|
||||
headers: authHeaders(credentials),
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
||||
|
||||
const fetchBlocks = ({credentials}) => {
|
||||
return promisedRequest(MASTODON_USER_BLOCKS_URL, { headers: authHeaders(credentials) })
|
||||
.then((users) => users.map(parseUser))
|
||||
}
|
||||
|
||||
const fetchOAuthTokens = ({credentials}) => {
|
||||
const url = '/api/oauth_tokens.json'
|
||||
|
||||
|
@ -618,8 +612,9 @@ const apiService = {
|
|||
deleteStatus,
|
||||
uploadMedia,
|
||||
fetchAllFollowing,
|
||||
setUserMute,
|
||||
fetchMutes,
|
||||
muteUser,
|
||||
unmuteUser,
|
||||
fetchBlocks,
|
||||
fetchOAuthTokens,
|
||||
revokeOAuthToken,
|
||||
|
|
|
@ -62,12 +62,10 @@ const backendInteractorService = (credentials) => {
|
|||
return timelineFetcherService.startFetching({timeline, store, credentials, userId, tag})
|
||||
}
|
||||
|
||||
const setUserMute = ({id, muted = true}) => {
|
||||
return apiService.setUserMute({id, muted, credentials})
|
||||
}
|
||||
|
||||
const fetchMutes = () => apiService.fetchMutes({credentials})
|
||||
const fetchBlocks = (params) => apiService.fetchBlocks({credentials, ...params})
|
||||
const muteUser = (id) => apiService.muteUser({credentials, id})
|
||||
const unmuteUser = (id) => apiService.unmuteUser({credentials, id})
|
||||
const fetchBlocks = () => apiService.fetchBlocks({credentials})
|
||||
const fetchFollowRequests = () => apiService.fetchFollowRequests({credentials})
|
||||
const fetchOAuthTokens = () => apiService.fetchOAuthTokens({credentials})
|
||||
const revokeOAuthToken = (id) => apiService.revokeOAuthToken({id, credentials})
|
||||
|
@ -100,8 +98,9 @@ const backendInteractorService = (credentials) => {
|
|||
fetchAllFollowing,
|
||||
verifyCredentials: apiService.verifyCredentials,
|
||||
startFetching,
|
||||
setUserMute,
|
||||
fetchMutes,
|
||||
muteUser,
|
||||
unmuteUser,
|
||||
fetchBlocks,
|
||||
fetchOAuthTokens,
|
||||
revokeOAuthToken,
|
||||
|
|
|
@ -19,6 +19,9 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false
|
|||
const args = { timeline, credentials }
|
||||
const rootState = store.rootState || store.state
|
||||
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
|
||||
const hideMutedPosts = typeof rootState.config.hideMutedPosts === 'undefined'
|
||||
? rootState.instance.hideMutedPosts
|
||||
: rootState.config.hideMutedPosts
|
||||
|
||||
if (older) {
|
||||
args['until'] = until || timelineData.minId
|
||||
|
@ -28,6 +31,7 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false
|
|||
|
||||
args['userId'] = userId
|
||||
args['tag'] = tag
|
||||
args['withMuted'] = !hideMutedPosts
|
||||
|
||||
const numStatusesBeforeFetch = timelineData.statuses.length
|
||||
|
||||
|
|
Loading…
Reference in a new issue