make relationships separate from users

This commit is contained in:
Shpuld Shpuldson 2020-04-21 23:27:51 +03:00
parent d5457c323a
commit 6bb75a3a6d
25 changed files with 112 additions and 81 deletions

View file

@ -304,6 +304,9 @@ const afterStoreSetup = async ({ store, i18n }) => {
getNodeInfo({ store }) getNodeInfo({ store })
]) ])
// Start fetching things that don't need to block the UI
store.dispatch('fetchMutes')
const router = new VueRouter({ const router = new VueRouter({
mode: 'history', mode: 'history',
routes: routes(store), routes: routes(store),

View file

@ -3,7 +3,7 @@ import Popover from '../popover/popover.vue'
const AccountActions = { const AccountActions = {
props: [ props: [
'user' 'user', 'relationship'
], ],
data () { data () {
return { } return { }

View file

@ -9,16 +9,16 @@
class="account-tools-popover" class="account-tools-popover"
> >
<div class="dropdown-menu"> <div class="dropdown-menu">
<template v-if="user.following"> <template v-if="relationship.following">
<button <button
v-if="user.showing_reblogs" v-if="relationship.showing_reblogs"
class="btn btn-default dropdown-item" class="btn btn-default dropdown-item"
@click="hideRepeats" @click="hideRepeats"
> >
{{ $t('user_card.hide_repeats') }} {{ $t('user_card.hide_repeats') }}
</button> </button>
<button <button
v-if="!user.showing_reblogs" v-if="!relationship.showing_reblogs"
class="btn btn-default dropdown-item" class="btn btn-default dropdown-item"
@click="showRepeats" @click="showRepeats"
> >
@ -30,7 +30,7 @@
/> />
</template> </template>
<button <button
v-if="user.statusnet_blocking" v-if="relationship.blocking"
class="btn btn-default btn-block dropdown-item" class="btn btn-default btn-block dropdown-item"
@click="unblockUser" @click="unblockUser"
> >

View file

@ -12,7 +12,7 @@
class="basic-user-card-expanded-content" class="basic-user-card-expanded-content"
> >
<UserCard <UserCard
:user="user" :userId="user.id"
:rounded="true" :rounded="true"
:bordered="true" :bordered="true"
/> />

View file

@ -11,8 +11,11 @@ const BlockCard = {
user () { user () {
return this.$store.getters.findUser(this.userId) return this.$store.getters.findUser(this.userId)
}, },
relationship () {
return this.$store.state.users.relationships[this.userId] || {}
},
blocked () { blocked () {
return this.user.statusnet_blocking return this.relationship.blocking
} }
}, },
components: { components: {

View file

@ -1,6 +1,6 @@
import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
export default { export default {
props: ['user', 'labelFollowing', 'buttonClass'], props: ['relationship', 'labelFollowing', 'buttonClass'],
data () { data () {
return { return {
inProgress: false inProgress: false
@ -8,12 +8,12 @@ export default {
}, },
computed: { computed: {
isPressed () { isPressed () {
return this.inProgress || this.user.following return this.inProgress || this.relationship.following
}, },
title () { title () {
if (this.inProgress || this.user.following) { if (this.inProgress || this.relationship.following) {
return this.$t('user_card.follow_unfollow') return this.$t('user_card.follow_unfollow')
} else if (this.user.requested) { } else if (this.relationship.requested) {
return this.$t('user_card.follow_again') return this.$t('user_card.follow_again')
} else { } else {
return this.$t('user_card.follow') return this.$t('user_card.follow')
@ -22,9 +22,9 @@ export default {
label () { label () {
if (this.inProgress) { if (this.inProgress) {
return this.$t('user_card.follow_progress') return this.$t('user_card.follow_progress')
} else if (this.user.following) { } else if (this.relationship.following) {
return this.labelFollowing || this.$t('user_card.following') return this.labelFollowing || this.$t('user_card.following')
} else if (this.user.requested) { } else if (this.relationship.requested) {
return this.$t('user_card.follow_sent') return this.$t('user_card.follow_sent')
} else { } else {
return this.$t('user_card.follow') return this.$t('user_card.follow')
@ -33,7 +33,7 @@ export default {
}, },
methods: { methods: {
onClick () { onClick () {
this.user.following ? this.unfollow() : this.follow() this.relationship.following ? this.unfollow() : this.follow()
}, },
follow () { follow () {
this.inProgress = true this.inProgress = true

View file

@ -18,6 +18,9 @@ const FollowCard = {
}, },
loggedIn () { loggedIn () {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
},
relationship () {
return this.$store.state.users.relationships[this.user.id]
} }
} }
} }

View file

@ -2,14 +2,14 @@
<basic-user-card :user="user"> <basic-user-card :user="user">
<div class="follow-card-content-container"> <div class="follow-card-content-container">
<span <span
v-if="!noFollowsYou && user.follows_you" v-if="!noFollowsYou && relationship.followed_by"
class="faint" class="faint"
> >
{{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }} {{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }}
</span> </span>
<template v-if="!loggedIn"> <template v-if="!loggedIn">
<div <div
v-if="!user.following" v-if="!relationship.following"
class="follow-card-follow-button" class="follow-card-follow-button"
> >
<RemoteFollow :user="user" /> <RemoteFollow :user="user" />
@ -18,6 +18,7 @@
<template v-else> <template v-else>
<FollowButton <FollowButton
:user="user" :user="user"
:relationship="relationship"
class="follow-card-follow-button" class="follow-card-follow-button"
:label-following="$t('user_card.follow_unfollow')" :label-following="$t('user_card.follow_unfollow')"
/> />

View file

@ -11,8 +11,11 @@ const MuteCard = {
user () { user () {
return this.$store.getters.findUser(this.userId) return this.$store.getters.findUser(this.userId)
}, },
relationship () {
return this.$store.state.users.relationships[this.userId]
},
muted () { muted () {
return this.user.muted return this.relationship.muting
} }
}, },
components: { components: {
@ -21,13 +24,13 @@ const MuteCard = {
methods: { methods: {
unmuteUser () { unmuteUser () {
this.progress = true this.progress = true
this.$store.dispatch('unmuteUser', this.user.id).then(() => { this.$store.dispatch('unmuteUser', this.userId).then(() => {
this.progress = false this.progress = false
}) })
}, },
muteUser () { muteUser () {
this.progress = true this.progress = true
this.$store.dispatch('muteUser', this.user.id).then(() => { this.$store.dispatch('muteUser', this.userId).then(() => {
this.progress = false this.progress = false
}) })
} }

View file

@ -56,7 +56,7 @@ const Notification = {
return this.generateUserProfileLink(this.targetUser) return this.generateUserProfileLink(this.targetUser)
}, },
needMute () { needMute () {
return this.user.muted return (this.$store.state.users.relationships[this.user.id] || {}).muting
} }
} }
} }

View file

@ -40,7 +40,7 @@
<div class="notification-right"> <div class="notification-right">
<UserCard <UserCard
v-if="userExpanded" v-if="userExpanded"
:user="getUser(notification)" :user-id="getUser(notification).id"
:rounded="true" :rounded="true"
:bordered="true" :bordered="true"
/> />

View file

@ -19,7 +19,7 @@
> >
<UserCard <UserCard
v-if="currentUser" v-if="currentUser"
:user="currentUser" :userId="currentUser.id"
:hide-bio="true" :hide-bio="true"
/> />
<div <div

View file

@ -118,7 +118,13 @@ const Status = {
return hits return hits
}, },
muted () { return !this.unmuted && ((!(this.inProfile && this.status.user.id === this.profileUserId) && this.status.user.muted) || (!this.inConversation && this.status.thread_muted) || this.muteWordHits.length > 0) }, muted () {
const relationship = this.$store.state.users.relationships[this.status.user.id] || {}
return !this.unmuted && (
(!(this.inProfile && this.status.user.id === this.profileUserId) && relationship.muting) ||
(!this.inConversation && this.status.thread_muted) ||
this.muteWordHits.length > 0)
},
hideFilteredStatuses () { hideFilteredStatuses () {
return this.mergedConfig.hideFilteredStatuses return this.mergedConfig.hideFilteredStatuses
}, },
@ -178,8 +184,11 @@ const Status = {
if (this.status.user.id === this.status.attentions[i].id) { if (this.status.user.id === this.status.attentions[i].id) {
continue continue
} }
const taggedUser = this.$store.getters.findUser(this.status.attentions[i].id) // There's zero guarantee of this working. If we happen to have that user and their
if (checkFollowing && taggedUser && taggedUser.following) { // relationship in store then it will work, but there's kinda little chance of having
// them for people you're not following.
const relationship = this.$store.state.users.relationships[this.status.attentions[i].id]
if (checkFollowing && relationship && relationship.following) {
return false return false
} }
if (this.status.attentions[i].id === this.currentUser.id) { if (this.status.attentions[i].id === this.currentUser.id) {

View file

@ -94,7 +94,7 @@
<div class="status-body"> <div class="status-body">
<UserCard <UserCard
v-if="userExpanded" v-if="userExpanded"
:user="status.user" :userId="status.user.id"
:rounded="true" :rounded="true"
:bordered="true" :bordered="true"
class="status-usercard" class="status-usercard"

View file

@ -9,7 +9,7 @@ import { mapGetters } from 'vuex'
export default { export default {
props: [ props: [
'user', 'switcher', 'selected', 'hideBio', 'rounded', 'bordered', 'allowZoomingAvatar' 'userId', 'switcher', 'selected', 'hideBio', 'rounded', 'bordered', 'allowZoomingAvatar'
], ],
data () { data () {
return { return {
@ -21,6 +21,12 @@ export default {
this.$store.dispatch('fetchUserRelationship', this.user.id) this.$store.dispatch('fetchUserRelationship', this.user.id)
}, },
computed: { computed: {
user () {
return this.$store.getters.findUser(this.userId)
},
relationship () {
return this.$store.state.users.relationships[this.userId] || {}
},
classes () { classes () {
return [{ return [{
'user-card-rounded-t': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius 'user-card-rounded-t': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius

View file

@ -8,7 +8,9 @@
:style="style" :style="style"
class="background-image" class="background-image"
/> />
<div class="panel-heading"> <div
class="panel-heading"
>
<div class="user-info"> <div class="user-info">
<div class="container"> <div class="container">
<a <a
@ -69,6 +71,7 @@
<AccountActions <AccountActions
v-if="isOtherUser && loggedIn" v-if="isOtherUser && loggedIn"
:user="user" :user="user"
:relationship="relationship"
/> />
</div> </div>
<div class="bottom-line"> <div class="bottom-line">
@ -92,7 +95,7 @@
</div> </div>
<div class="user-meta"> <div class="user-meta">
<div <div
v-if="user.follows_you && loggedIn && isOtherUser" v-if="relationship.followed_by && loggedIn && isOtherUser"
class="following" class="following"
> >
{{ $t('user_card.follows_you') }} {{ $t('user_card.follows_you') }}
@ -139,10 +142,10 @@
class="user-interactions" class="user-interactions"
> >
<div class="btn-group"> <div class="btn-group">
<FollowButton :user="user" /> <FollowButton :relationship="relationship" />
<template v-if="user.following"> <template v-if="relationship.following">
<ProgressButton <ProgressButton
v-if="!user.subscribed" v-if="!relationship.subscribing"
class="btn btn-default" class="btn btn-default"
:click="subscribeUser" :click="subscribeUser"
:title="$t('user_card.subscribe')" :title="$t('user_card.subscribe')"
@ -161,7 +164,7 @@
</div> </div>
<div> <div>
<button <button
v-if="user.muted" v-if="relationship.muting"
class="btn btn-default btn-block toggled" class="btn btn-default btn-block toggled"
@click="unmuteUser" @click="unmuteUser"
> >

View file

@ -6,7 +6,7 @@
class="panel panel-default signed-in" class="panel panel-default signed-in"
> >
<UserCard <UserCard
:user="user" :userId="user.id"
:hide-bio="true" :hide-bio="true"
rounded="top" rounded="top"
/> />

View file

@ -5,7 +5,7 @@
class="user-profile panel panel-default" class="user-profile panel panel-default"
> >
<UserCard <UserCard
:user="user" :userId="user.id"
:switcher="true" :switcher="true"
:selected="timeline.viewing" :selected="timeline.viewing"
:allow-zooming-avatar="true" :allow-zooming-avatar="true"

View file

@ -351,14 +351,14 @@ const UserSettings = {
}, },
filterUnblockedUsers (userIds) { filterUnblockedUsers (userIds) {
return reject(userIds, (userId) => { return reject(userIds, (userId) => {
const user = this.$store.getters.findUser(userId) const relationship = this.$store.state.users.relationships[userId] || {}
return !user || user.statusnet_blocking || user.id === this.$store.state.users.currentUser.id return relationship.blocking || userId === this.$store.state.users.currentUser.id
}) })
}, },
filterUnMutedUsers (userIds) { filterUnMutedUsers (userIds) {
return reject(userIds, (userId) => { return reject(userIds, (userId) => {
const user = this.$store.getters.findUser(userId) const relationship = this.$store.state.users.relationships[userId] || {}
return !user || user.muted || user.id === this.$store.state.users.currentUser.id return relationship.muting || userId === this.$store.state.users.currentUser.id
}) })
}, },
queryUserIds (query) { queryUserIds (query) {

View file

@ -146,26 +146,19 @@ export const mutations = {
} }
}, },
addNewUsers (state, users) { addNewUsers (state, users) {
each(users, (user) => mergeOrAdd(state.users, state.usersObject, user)) each(users, (user) => {
// console.log(user)
if (user.relationship) {
set(state.relationships, user.relationship.id, user.relationship)
}
mergeOrAdd(state.users, state.usersObject, user)
})
}, },
updateUserRelationship (state, relationships) { updateUserRelationship (state, relationships) {
relationships.forEach((relationship) => { relationships.forEach((relationship) => {
const user = state.usersObject[relationship.id] set(state.relationships, relationship.id, relationship)
if (user) {
user.follows_you = relationship.followed_by
user.following = relationship.following
user.muted = relationship.muting
user.statusnet_blocking = relationship.blocking
user.subscribed = relationship.subscribing
user.showing_reblogs = relationship.showing_reblogs
}
}) })
}, },
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) { saveBlockIds (state, blockIds) {
state.currentUser.blockIds = blockIds state.currentUser.blockIds = blockIds
}, },
@ -174,11 +167,6 @@ export const mutations = {
state.currentUser.blockIds.push(blockId) state.currentUser.blockIds.push(blockId)
} }
}, },
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) { saveMuteIds (state, muteIds) {
state.currentUser.muteIds = muteIds state.currentUser.muteIds = muteIds
}, },
@ -254,7 +242,8 @@ export const defaultState = {
users: [], users: [],
usersObject: {}, usersObject: {},
signUpPending: false, signUpPending: false,
signUpErrors: [] signUpErrors: [],
relationships: {}
} }
const users = { const users = {
@ -279,7 +268,7 @@ const users = {
return store.rootState.api.backendInteractor.fetchBlocks() return store.rootState.api.backendInteractor.fetchBlocks()
.then((blocks) => { .then((blocks) => {
store.commit('saveBlockIds', map(blocks, 'id')) store.commit('saveBlockIds', map(blocks, 'id'))
store.commit('updateBlocks', blocks) store.commit('addNewUsers', blocks)
return blocks return blocks
}) })
}, },
@ -298,8 +287,8 @@ const users = {
fetchMutes (store) { fetchMutes (store) {
return store.rootState.api.backendInteractor.fetchMutes() return store.rootState.api.backendInteractor.fetchMutes()
.then((mutes) => { .then((mutes) => {
store.commit('updateMutes', mutes)
store.commit('saveMuteIds', map(mutes, 'id')) store.commit('saveMuteIds', map(mutes, 'id'))
store.commit('addNewUsers', mutes)
return mutes return mutes
}) })
}, },
@ -416,7 +405,7 @@ const users = {
}, },
addNewNotifications (store, { notifications }) { addNewNotifications (store, { notifications }) {
const users = map(notifications, 'from_profile') const users = map(notifications, 'from_profile')
const targetUsers = map(notifications, 'target') const targetUsers = map(notifications, 'target').filter(_ => _)
const notificationIds = notifications.map(_ => _.id) const notificationIds = notifications.map(_ => _.id)
store.commit('addNewUsers', users) store.commit('addNewUsers', users)
store.commit('addNewUsers', targetUsers) store.commit('addNewUsers', targetUsers)

View file

@ -496,7 +496,8 @@ const fetchTimeline = ({
userId = false, userId = false,
tag = false, tag = false,
withMuted = false, withMuted = false,
withMove = false withMove = false,
withRelationships = false
}) => { }) => {
const timelineUrls = { const timelineUrls = {
public: MASTODON_PUBLIC_TIMELINE, public: MASTODON_PUBLIC_TIMELINE,
@ -542,6 +543,7 @@ const fetchTimeline = ({
params.push(['count', 20]) params.push(['count', 20])
params.push(['with_muted', withMuted]) params.push(['with_muted', withMuted])
params.push(['with_relationships', withRelationships])
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&') const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
url += `?${queryString}` url += `?${queryString}`

View file

@ -73,7 +73,7 @@ export const parseUser = (data) => {
output.background_image = data.pleroma.background_image output.background_image = data.pleroma.background_image
output.token = data.pleroma.chat_token output.token = data.pleroma.chat_token
if (relationship) { if (relationship && !relationship) {
output.follows_you = relationship.followed_by output.follows_you = relationship.followed_by
output.requested = relationship.requested output.requested = relationship.requested
output.following = relationship.following output.following = relationship.following
@ -82,6 +82,9 @@ export const parseUser = (data) => {
output.showing_reblogs = relationship.showing_reblogs output.showing_reblogs = relationship.showing_reblogs
output.subscribed = relationship.subscribing output.subscribed = relationship.subscribing
} }
if (relationship) {
output.relationship = relationship
}
output.allow_following_move = data.pleroma.allow_following_move output.allow_following_move = data.pleroma.allow_following_move
@ -137,16 +140,10 @@ export const parseUser = (data) => {
output.statusnet_profile_url = data.statusnet_profile_url output.statusnet_profile_url = data.statusnet_profile_url
output.statusnet_blocking = data.statusnet_blocking
output.is_local = data.is_local output.is_local = data.is_local
output.role = data.role output.role = data.role
output.show_role = data.show_role output.show_role = data.show_role
output.follows_you = data.follows_you
output.muted = data.muted
if (data.rights) { if (data.rights) {
output.rights = { output.rights = {
moderator: data.rights.delete_others_notice, moderator: data.rights.delete_others_notice,
@ -160,10 +157,16 @@ export const parseUser = (data) => {
output.hide_follows_count = data.hide_follows_count output.hide_follows_count = data.hide_follows_count
output.hide_followers_count = data.hide_followers_count output.hide_followers_count = data.hide_followers_count
output.background_image = data.background_image output.background_image = data.background_image
// on mastoapi this info is contained in a "relationship"
output.following = data.following
// Websocket token // Websocket token
output.token = data.token output.token = data.token
// Convert relationsip data to expected format
output.relationship = {
muting: data.muted,
blocking: data.statusnet_blocking,
followed_by: data.follows_you,
following: data.following
}
} }
output.created_at = new Date(data.created_at) output.created_at = new Date(data.created_at)
@ -317,6 +320,9 @@ export const parseStatus = (data) => {
? String(output.in_reply_to_user_id) ? String(output.in_reply_to_user_id)
: null : null
if (data.account.pleroma.relationship) {
data.account.pleroma.relationship = undefined
}
output.user = parseUser(masto ? data.account : data.user) output.user = parseUser(masto ? data.account : data.user)
output.attentions = ((masto ? data.mentions : data.attentions) || []).map(parseUser) output.attentions = ((masto ? data.mentions : data.attentions) || []).map(parseUser)
@ -342,7 +348,6 @@ export const parseNotification = (data) => {
} }
const masto = !data.hasOwnProperty('ntype') const masto = !data.hasOwnProperty('ntype')
const output = {} const output = {}
if (masto) { if (masto) {
output.type = mastoDict[data.type] || data.type output.type = mastoDict[data.type] || data.type
output.seen = data.pleroma.is_seen output.seen = data.pleroma.is_seen

View file

@ -1,15 +1,18 @@
const fetchUser = (attempt, user, store) => new Promise((resolve, reject) => { const fetchRelationship = (attempt, user, store) => new Promise((resolve, reject) => {
setTimeout(() => { setTimeout(() => {
store.state.api.backendInteractor.fetchUser({ id: user.id }) store.state.api.backendInteractor.fetchUserRelationship({ id: user.id })
.then((user) => store.commit('addNewUsers', [user])) .then((relationship) => {
.then(() => resolve([user.following, user.requested, user.locked, attempt])) store.commit('updateUserRelationship', [relationship])
return relationship
})
.then((relationship) => resolve([relationship.following, relationship.requested, user.locked, attempt]))
.catch((e) => reject(e)) .catch((e) => reject(e))
}, 500) }, 500)
}).then(([following, sent, locked, attempt]) => { }).then(([following, sent, locked, attempt]) => {
if (!following && !(locked && sent) && attempt <= 3) { if (!following && !(locked && sent) && attempt <= 3) {
// If we BE reports that we still not following that user - retry, // If we BE reports that we still not following that user - retry,
// increment attempts by one // increment attempts by one
fetchUser(++attempt, user, store) fetchRelationship(++attempt, user, store)
} }
}) })
@ -31,7 +34,7 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
// don't know that yet. // don't know that yet.
// Recursive Promise, it will call itself up to 3 times. // Recursive Promise, it will call itself up to 3 times.
return fetchUser(1, user, store) return fetchRelationship(1, user, store)
.then(() => { .then(() => {
resolve() resolve()
}) })

View file

@ -48,7 +48,6 @@ const fetchNotifications = ({ store, args, older }) => {
update({ store, notifications, older }) update({ store, notifications, older })
return notifications return notifications
}, () => store.dispatch('setNotificationsError', { value: true })) }, () => store.dispatch('setNotificationsError', { value: true }))
.catch(() => store.dispatch('setNotificationsError', { value: true }))
} }
const startFetching = ({ credentials, store }) => { const startFetching = ({ credentials, store }) => {

View file

@ -31,6 +31,7 @@ const fetchAndUpdate = ({
const { getters } = store const { getters } = store
const timelineData = rootState.statuses.timelines[camelCase(timeline)] const timelineData = rootState.statuses.timelines[camelCase(timeline)]
const hideMutedPosts = getters.mergedConfig.hideMutedPosts const hideMutedPosts = getters.mergedConfig.hideMutedPosts
const replyVisibility = getters.mergedConfig.replyVisibility
if (older) { if (older) {
args['until'] = until || timelineData.minId args['until'] = until || timelineData.minId
@ -41,6 +42,7 @@ const fetchAndUpdate = ({
args['userId'] = userId args['userId'] = userId
args['tag'] = tag args['tag'] = tag
args['withMuted'] = !hideMutedPosts args['withMuted'] = !hideMutedPosts
args['withRelationships'] = replyVisibility === 'following'
const numStatusesBeforeFetch = timelineData.statuses.length const numStatusesBeforeFetch = timelineData.statuses.length