initial pinia implementation
This commit is contained in:
parent
92e8190f63
commit
32b9c4a14d
3 changed files with 735 additions and 23 deletions
|
|
@ -1,14 +1,16 @@
|
||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
import { required, requiredIf, sameAs } from '@vuelidate/validators'
|
import { required, requiredIf, sameAs } from '@vuelidate/validators'
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapActions, mapState } from 'pinia'
|
||||||
import { mapActions, mapState } from 'vuex'
|
|
||||||
|
|
||||||
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
||||||
import TermsOfServicePanel from 'src/components/terms_of_service_panel/terms_of_service_panel.vue'
|
import TermsOfServicePanel from 'src/components/terms_of_service_panel/terms_of_service_panel.vue'
|
||||||
import localeService from '../../services/locale/locale.service.js'
|
import localeService from '../../services/locale/locale.service.js'
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
|
import { getCaptcha, register } from 'src/api/public.js'
|
||||||
import { DAY } from 'src/services/date_utils/date_utils.js'
|
import { DAY } from 'src/services/date_utils/date_utils.js'
|
||||||
|
|
||||||
const registration = {
|
const registration = {
|
||||||
|
|
@ -26,6 +28,9 @@ const registration = {
|
||||||
reason: '',
|
reason: '',
|
||||||
language: [''],
|
language: [''],
|
||||||
},
|
},
|
||||||
|
signUpPending: false,
|
||||||
|
signUpErrors: [],
|
||||||
|
signUpNotice: {},
|
||||||
captcha: {},
|
captcha: {},
|
||||||
}),
|
}),
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -58,7 +63,7 @@ const registration = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if ((!this.registrationOpen && !this.token) || this.signedIn) {
|
if ((!this.registrationOpen && !this.token) || this.loggedIn) {
|
||||||
this.$router.push({ name: 'root' })
|
this.$router.push({ name: 'root' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +105,10 @@ const registration = {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
...mapPiniaState(useInstanceStore, {
|
hasSignUpNotice(state) {
|
||||||
|
return this.signUpNotice.message
|
||||||
|
},
|
||||||
|
...mapState(useInstanceStore, {
|
||||||
registrationOpen: (store) => store.registrationOpen,
|
registrationOpen: (store) => store.registrationOpen,
|
||||||
embeddedToS: (store) => store.embeddedToS,
|
embeddedToS: (store) => store.embeddedToS,
|
||||||
termsOfService: (store) => store.tos,
|
termsOfService: (store) => store.tos,
|
||||||
|
|
@ -109,16 +117,49 @@ const registration = {
|
||||||
birthdayRequired: (store) => store.birthdayRequired,
|
birthdayRequired: (store) => store.birthdayRequired,
|
||||||
birthdayMinAge: (store) => store.birthdayMinAge,
|
birthdayMinAge: (store) => store.birthdayMinAge,
|
||||||
}),
|
}),
|
||||||
...mapState({
|
...mapState(useUsersStore, ['loggedIn']),
|
||||||
signedIn: (state) => !!state.users.currentUser,
|
|
||||||
isPending: (state) => state.users.signUpPending,
|
|
||||||
serverValidationErrors: (state) => state.users.signUpErrors,
|
|
||||||
signUpNotice: (state) => state.users.signUpNotice,
|
|
||||||
hasSignUpNotice: (state) => !!state.users.signUpNotice.message,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['signUp', 'getCaptcha']),
|
...mapActions(useUsersStore, ['loginUser']),
|
||||||
|
getCaptcha(store) {
|
||||||
|
return getCaptcha({
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data }) => data)
|
||||||
|
},
|
||||||
|
async signUp(userInfo) {
|
||||||
|
const oauthStore = useOAuthStore()
|
||||||
|
|
||||||
|
this.signUpPending = true
|
||||||
|
this.signUpErrors = []
|
||||||
|
this.signUpNotice = {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const token = await oauthStore.ensureAppToken()
|
||||||
|
const { data } = await register({
|
||||||
|
credentials: token,
|
||||||
|
params: { ...userInfo },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (data.access_token) {
|
||||||
|
this.signUpPending = false
|
||||||
|
oauthStore.setToken(data.access_token)
|
||||||
|
await this.loginUser(data.access_token)
|
||||||
|
return 'ok'
|
||||||
|
} else {
|
||||||
|
// Request succeeded, but user cannot login yet.
|
||||||
|
this.signUpErrors = []
|
||||||
|
this.signUpNotice = data
|
||||||
|
return 'request_sent'
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
const errors = e.message
|
||||||
|
this.signUpErrors = errors
|
||||||
|
this.signUpNotice = {}
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
this.signUpPending = false
|
||||||
|
}
|
||||||
|
},
|
||||||
async submit() {
|
async submit() {
|
||||||
this.user.nickname = this.user.username
|
this.user.nickname = this.user.username
|
||||||
this.user.token = this.token
|
this.user.token = this.token
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
<input
|
<input
|
||||||
id="sign-up-username"
|
id="sign-up-username"
|
||||||
v-model.trim="v$.user.username.$model"
|
v-model.trim="v$.user.username.$model"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
:aria-required="true"
|
:aria-required="true"
|
||||||
:placeholder="$t('registration.username_placeholder')"
|
:placeholder="$t('registration.username_placeholder')"
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
<input
|
<input
|
||||||
id="sign-up-fullname"
|
id="sign-up-fullname"
|
||||||
v-model.trim="v$.user.fullname.$model"
|
v-model.trim="v$.user.fullname.$model"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
:aria-required="true"
|
:aria-required="true"
|
||||||
:placeholder="$t('registration.fullname_placeholder')"
|
:placeholder="$t('registration.fullname_placeholder')"
|
||||||
|
|
@ -84,7 +84,7 @@
|
||||||
<input
|
<input
|
||||||
id="email"
|
id="email"
|
||||||
v-model="v$.user.email.$model"
|
v-model="v$.user.email.$model"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
type="email"
|
type="email"
|
||||||
:aria-required="accountActivationRequired"
|
:aria-required="accountActivationRequired"
|
||||||
|
|
@ -109,7 +109,7 @@
|
||||||
<textarea
|
<textarea
|
||||||
id="bio"
|
id="bio"
|
||||||
v-model="user.bio"
|
v-model="user.bio"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
:placeholder="bioPlaceholder"
|
:placeholder="bioPlaceholder"
|
||||||
/>
|
/>
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
<input
|
<input
|
||||||
id="sign-up-password"
|
id="sign-up-password"
|
||||||
v-model="user.password"
|
v-model="user.password"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
type="password"
|
type="password"
|
||||||
:aria-required="true"
|
:aria-required="true"
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
<input
|
<input
|
||||||
id="sign-up-password-confirmation"
|
id="sign-up-password-confirmation"
|
||||||
v-model="user.confirm"
|
v-model="user.confirm"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
type="password"
|
type="password"
|
||||||
:aria-required="true"
|
:aria-required="true"
|
||||||
|
|
@ -187,7 +187,7 @@
|
||||||
<input
|
<input
|
||||||
id="sign-up-birthday"
|
id="sign-up-birthday"
|
||||||
v-model="user.birthday"
|
v-model="user.birthday"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
type="date"
|
type="date"
|
||||||
:max="birthdayRequired ? birthdayMinAttr : undefined"
|
:max="birthdayRequired ? birthdayMinAttr : undefined"
|
||||||
|
|
@ -232,7 +232,7 @@
|
||||||
<textarea
|
<textarea
|
||||||
id="reason"
|
id="reason"
|
||||||
v-model="user.reason"
|
v-model="user.reason"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
:placeholder="reasonPlaceholder"
|
:placeholder="reasonPlaceholder"
|
||||||
/>
|
/>
|
||||||
|
|
@ -259,7 +259,7 @@
|
||||||
<input
|
<input
|
||||||
id="captcha-answer"
|
id="captcha-answer"
|
||||||
v-model="captcha.solution"
|
v-model="captcha.solution"
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
class="input form-control"
|
class="input form-control"
|
||||||
type="text"
|
type="text"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
|
|
@ -285,7 +285,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button
|
<button
|
||||||
:disabled="isPending"
|
:disabled="signUpPending"
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn button-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
|
|
@ -308,7 +308,7 @@
|
||||||
>
|
>
|
||||||
<div class="alert error">
|
<div class="alert error">
|
||||||
<span
|
<span
|
||||||
v-for="error in serverValidationErrors"
|
v-for="error in signUpErrors"
|
||||||
:key="error"
|
:key="error"
|
||||||
>{{ error }}</span>
|
>{{ error }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
671
src/stores/users.js
Normal file
671
src/stores/users.js
Normal file
|
|
@ -0,0 +1,671 @@
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
import { last, map } from 'lodash'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
import {
|
||||||
|
registerPushNotifications,
|
||||||
|
unregisterPushNotifications,
|
||||||
|
} from '../services/sw/sw.js'
|
||||||
|
import {
|
||||||
|
windowHeight,
|
||||||
|
windowWidth,
|
||||||
|
} from '../services/window_utils/window_utils'
|
||||||
|
|
||||||
|
import { useAnnouncementsStore } from 'src/stores/announcements.js'
|
||||||
|
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
|
||||||
|
import { useChatsStore } from 'src/stores/chats.js'
|
||||||
|
import { useEmojiStore } from 'src/stores/emoji.js'
|
||||||
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
import { useListsStore } from 'src/stores/lists.js'
|
||||||
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
||||||
|
|
||||||
|
import { revokeToken } from 'src/api/oauth.js'
|
||||||
|
import {
|
||||||
|
fetchFollowers,
|
||||||
|
fetchFriends,
|
||||||
|
fetchUser,
|
||||||
|
fetchUserByName,
|
||||||
|
searchUsers,
|
||||||
|
verifyCredentials,
|
||||||
|
} from 'src/api/public.js'
|
||||||
|
import {
|
||||||
|
blockUser,
|
||||||
|
editUserNote,
|
||||||
|
fetchBlocks,
|
||||||
|
fetchDomainMutes,
|
||||||
|
fetchMutes,
|
||||||
|
fetchUserInLists,
|
||||||
|
fetchUserRelationship,
|
||||||
|
followUser,
|
||||||
|
muteDomain,
|
||||||
|
muteUser,
|
||||||
|
removeUserFromFollowers,
|
||||||
|
unblockUser,
|
||||||
|
unmuteDomain,
|
||||||
|
unmuteUser,
|
||||||
|
} from 'src/api/user.js'
|
||||||
|
|
||||||
|
const getNotificationPermission = async () => {
|
||||||
|
const Notification = window.Notification
|
||||||
|
|
||||||
|
if (!Notification) return null
|
||||||
|
if (Notification.permission === 'default')
|
||||||
|
return Notification.requestPermission()
|
||||||
|
return Notification.permission
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultState = {
|
||||||
|
loggingIn: false,
|
||||||
|
lastLoginName: null,
|
||||||
|
currentUser: null,
|
||||||
|
users: new Map(),
|
||||||
|
usersByName: new Map(),
|
||||||
|
usersByURL: new Map(),
|
||||||
|
relationships: new Map(),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useUsersStore = defineStore('users', {
|
||||||
|
state: defaultState,
|
||||||
|
getters: {
|
||||||
|
loggedIn: (state) => !!state.currentUser,
|
||||||
|
findUser: (state) => (query) => {
|
||||||
|
return state.users.get(query)
|
||||||
|
},
|
||||||
|
findUserByName: (state) => (query) => {
|
||||||
|
return state.usersByName.get(query.toLowerCase())
|
||||||
|
},
|
||||||
|
findUserByUrl: (state) => (query) => {
|
||||||
|
return state.usersByURL.get(query.toLowerCase())
|
||||||
|
},
|
||||||
|
relationship: (state) => (id) => {
|
||||||
|
const rel = id && state.relationships.get(id)
|
||||||
|
return rel || { id, loading: true }
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
tagUser({ user: { id }, tag }) {
|
||||||
|
const user = this.users.get(id)
|
||||||
|
user.tags.add(tag)
|
||||||
|
},
|
||||||
|
untagUser({ user: { id }, tag }) {
|
||||||
|
const user = this.users.get(id)
|
||||||
|
user.tags.delete(tag)
|
||||||
|
},
|
||||||
|
updateRight({ user: { id }, right, value }) {
|
||||||
|
const user = this.users.get(id)
|
||||||
|
const newRights = user.rights
|
||||||
|
newRights[right] = value
|
||||||
|
user.rights = newRights
|
||||||
|
},
|
||||||
|
async updateUserAdminData({ user }) {
|
||||||
|
const localUser = await this.fetchUserIfMissing(user.id)
|
||||||
|
|
||||||
|
localUser.adminData = user
|
||||||
|
localUser.deactivated = !user.is_active
|
||||||
|
localUser.tags = new Set(user.tags)
|
||||||
|
},
|
||||||
|
setCurrentUser(user) {
|
||||||
|
this.lastLoginName = user.screen_name
|
||||||
|
this.currentUser = user
|
||||||
|
},
|
||||||
|
clearCurrentUser() {
|
||||||
|
this.currentUser = null
|
||||||
|
this.lastLoginName = null
|
||||||
|
},
|
||||||
|
saveFriendIds({ id, friendIds }) {
|
||||||
|
const user = this.users.get(id)
|
||||||
|
user.friendIds = [...new Set([...(user.friendIds || []), ...friendIds])]
|
||||||
|
},
|
||||||
|
saveFollowerIds({ id, followerIds }) {
|
||||||
|
const user = this.users.get(id)
|
||||||
|
user.followerIds = [...new Set([user.followerIds || [], ...followerIds])]
|
||||||
|
},
|
||||||
|
// Because frontend doesn't have a reason to keep these stuff in memory
|
||||||
|
// outside of viewing someones user profile.
|
||||||
|
clearFriends(userId) {
|
||||||
|
const user = this.users.get(userId)
|
||||||
|
if (user) {
|
||||||
|
user.friendIds = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearFollowers(userId) {
|
||||||
|
const user = this.users.get(userId)
|
||||||
|
if (user) {
|
||||||
|
user.followerIds = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addNewUsers(users, timestamp) {
|
||||||
|
users.forEach((user) => {
|
||||||
|
const existing = users.get(user.id) ?? {}
|
||||||
|
|
||||||
|
const { relationship, ...old } = existing
|
||||||
|
const { relationshop, ...neu } = user
|
||||||
|
const newUser = { ...old, ...neu }
|
||||||
|
|
||||||
|
this.users.set(user.id, newUser)
|
||||||
|
this.usersByName.set(user.screen_name.toLowerCase(), newUser)
|
||||||
|
this.usersByURL.set(user.url.toLowerCase(), newUser)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateUserRelationship(relationships) {
|
||||||
|
relationships.forEach((relationship) => {
|
||||||
|
this.relationships[relationship.id] = relationship
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateUserInLists({ id, inLists }) {
|
||||||
|
this.users.get(id).inLists = inLists
|
||||||
|
},
|
||||||
|
saveBlockIds(blockIds) {
|
||||||
|
this.currentUser.blockIds = blockIds
|
||||||
|
},
|
||||||
|
addBlockId(blockId) {
|
||||||
|
if (this.currentUser.blockIds.includes(blockId)) {
|
||||||
|
this.currentUser.blockIds.push(blockId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setBlockIdsMaxId(blockIdsMaxId) {
|
||||||
|
this.currentUser.blockIdsMaxId = blockIdsMaxId
|
||||||
|
},
|
||||||
|
saveMuteIds(muteIds) {
|
||||||
|
this.currentUser.muteIds = muteIds
|
||||||
|
},
|
||||||
|
setMuteIdsMaxId(muteIdsMaxId) {
|
||||||
|
this.currentUser.muteIdsMaxId = muteIdsMaxId
|
||||||
|
},
|
||||||
|
addMuteId(muteId) {
|
||||||
|
if (this.currentUser.muteIds.includes(muteId)) {
|
||||||
|
this.currentUser.muteIds.push(muteId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
saveDomainMutes(domainMutes) {
|
||||||
|
this.currentUser.domainMutes = domainMutes
|
||||||
|
},
|
||||||
|
addDomainMute(domain) {
|
||||||
|
if (this.currentUser.domainMutes.includes(domain)) {
|
||||||
|
this.currentUser.domainMutes.push(domain)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeDomainMute(domain) {
|
||||||
|
const index = this.currentUser.domainMutes.indexOf(domain)
|
||||||
|
if (index !== -1) {
|
||||||
|
this.currentUser.domainMutes.splice(index, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setPinnedToUser(status) {
|
||||||
|
const user = this.users.get(status.user.id)
|
||||||
|
user.pinnedStatusIds = user.pinnedStatusIds || []
|
||||||
|
const index = user.pinnedStatusIds.indexOf(status.id)
|
||||||
|
|
||||||
|
if (status.pinned && index === -1) {
|
||||||
|
user.pinnedStatusIds.push(status.id)
|
||||||
|
} else if (!status.pinned && index !== -1) {
|
||||||
|
user.pinnedStatusIds.splice(index, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setUserForStatus(status) {
|
||||||
|
status.user = this.users.get(status.user.id)
|
||||||
|
},
|
||||||
|
setUserForNotification(notification) {
|
||||||
|
if (notification.type !== 'follow') {
|
||||||
|
notification.action.user = this.users.get(notification.action.user.id)
|
||||||
|
}
|
||||||
|
notification.from_profile = this.users.get(notification.from_profile.id)
|
||||||
|
},
|
||||||
|
async fetchUserIfMissing(id) {
|
||||||
|
const user = this.findUser(id)
|
||||||
|
if (!user) {
|
||||||
|
return this.fetchUser(id)
|
||||||
|
} else {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchUser(id) {
|
||||||
|
return fetchUser({
|
||||||
|
id,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
})
|
||||||
|
.then(({ data: user }) => {
|
||||||
|
this.addNewUsers([user])
|
||||||
|
return user
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (error.statusCode === 404) {
|
||||||
|
console.warn(`User ${id} not found`)
|
||||||
|
} else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchUserByName(name) {
|
||||||
|
return fetchUserByName({
|
||||||
|
name,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: user }) => {
|
||||||
|
this.addNewUsers([user])
|
||||||
|
return user
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchUserRelationship(id) {
|
||||||
|
if (this.currentUser) {
|
||||||
|
fetchUserRelationship({
|
||||||
|
id,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: relationships }) =>
|
||||||
|
this.updateUserRelationship(relationships),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchUserInLists(id) {
|
||||||
|
if (this.currentUser) {
|
||||||
|
fetchUserInLists({
|
||||||
|
id,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: inLists }) => this.updateUserInLists({ id, inLists }))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchBlocks(args) {
|
||||||
|
const { reset } = args || {}
|
||||||
|
|
||||||
|
const maxId = this.currentUser.blockIdsMaxId
|
||||||
|
return fetchBlocks({
|
||||||
|
maxId,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: blocks }) => {
|
||||||
|
if (reset) {
|
||||||
|
this.saveBlockIds(blocks.map(({ id }) => id))
|
||||||
|
} else {
|
||||||
|
blocks.forEach(({ id }) => this.addBlockId(id))
|
||||||
|
}
|
||||||
|
if (blocks.length) {
|
||||||
|
this.setBlockIdsMaxId(last(blocks).id)
|
||||||
|
}
|
||||||
|
this.addNewUsers(blocks)
|
||||||
|
return blocks
|
||||||
|
})
|
||||||
|
},
|
||||||
|
blockUser(id, expiresIn = 0) {
|
||||||
|
const store = window.vuex
|
||||||
|
|
||||||
|
const predictedRelationship = this.relationships[id] || { id }
|
||||||
|
this.updateUserRelationship([predictedRelationship])
|
||||||
|
this.addBlockId(id)
|
||||||
|
|
||||||
|
return blockUser({ id, expiresIn }).then(({ data: relationship }) => {
|
||||||
|
this.updateUserRelationship([relationship])
|
||||||
|
this.addBlockId(id)
|
||||||
|
|
||||||
|
store.commit('removeStatus', { timeline: 'friends', userId: id })
|
||||||
|
store.commit('removeStatus', { timeline: 'public', userId: id })
|
||||||
|
store.commit('removeStatus', {
|
||||||
|
timeline: 'publicAndExternal',
|
||||||
|
userId: id,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
unblockUser(id) {
|
||||||
|
return unblockUser({ id }).then(({ data: relationship }) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
removeUserFromFollowers(id) {
|
||||||
|
return removeUserFromFollowers({ id }).then((relationship) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
blockUsers(data = []) {
|
||||||
|
return Promise.all(data.map((d) => this.blockUser(d)))
|
||||||
|
},
|
||||||
|
unblockUsers(data = []) {
|
||||||
|
return Promise.all(data.map((d) => unblockUser(d)))
|
||||||
|
},
|
||||||
|
editUserNote({ id, comment }) {
|
||||||
|
return editUserNote({ id, comment }).then((relationship) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
fetchMutes(args) {
|
||||||
|
const { reset } = args || {}
|
||||||
|
|
||||||
|
const maxId = this.currentUser.muteIdsMaxId
|
||||||
|
return fetchMutes({
|
||||||
|
maxId,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: mutes }) => {
|
||||||
|
if (reset) {
|
||||||
|
this.saveMuteIds(mutes.map(({ id }) => id))
|
||||||
|
} else {
|
||||||
|
mutes.forEach(({ id }) => this.addMuteId(id))
|
||||||
|
}
|
||||||
|
if (mutes.length) {
|
||||||
|
this.setMuteIdsMaxId(last(mutes).id)
|
||||||
|
}
|
||||||
|
this.addNewUsers(mutes)
|
||||||
|
return mutes
|
||||||
|
})
|
||||||
|
},
|
||||||
|
muteUser(id, expiresIn = 0) {
|
||||||
|
const predictedRelationship = this.relationships[id] || { id }
|
||||||
|
this.updateUserRelationship([predictedRelationship])
|
||||||
|
this.addMuteId(id)
|
||||||
|
|
||||||
|
return muteUser({
|
||||||
|
id,
|
||||||
|
expiresIn,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: relationship }) => {
|
||||||
|
this.updateUserRelationship([relationship])
|
||||||
|
this.addMuteId(id)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
unmuteUser(id) {
|
||||||
|
const predictedRelationship = this.relationships[id] || { id }
|
||||||
|
predictedRelationship.muting = false
|
||||||
|
this.updateUserRelationship([predictedRelationship])
|
||||||
|
|
||||||
|
return unmuteUser({ id }).then(({ data: relationship }) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
hideReblogs(id) {
|
||||||
|
return followUser({
|
||||||
|
id,
|
||||||
|
reblogs: false,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: relationship }) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
showReblogs(id) {
|
||||||
|
return followUser({
|
||||||
|
id,
|
||||||
|
reblogs: true,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: relationship }) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
muteUsers(data = []) {
|
||||||
|
return Promise.all(data.map((d) => this.muteUser(d)))
|
||||||
|
},
|
||||||
|
unmuteUsers(ids = []) {
|
||||||
|
return Promise.all(ids.map((d) => this.unmuteUser(d)))
|
||||||
|
},
|
||||||
|
fetchDomainMutes() {
|
||||||
|
return fetchDomainMutes({
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: domainMutes }) => {
|
||||||
|
this.saveDomainMutes(domainMutes)
|
||||||
|
return domainMutes
|
||||||
|
})
|
||||||
|
},
|
||||||
|
muteDomain(domain) {
|
||||||
|
return muteDomain({
|
||||||
|
domain,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(() => this.addDomainMute(domain))
|
||||||
|
},
|
||||||
|
unmuteDomain(domain) {
|
||||||
|
return unmuteDomain({
|
||||||
|
domain,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(() => this.removeDomainMute(domain))
|
||||||
|
},
|
||||||
|
muteDomains(domains = []) {
|
||||||
|
return Promise.all(domains.map((domain) => this.muteDomain(domain)))
|
||||||
|
},
|
||||||
|
unmuteDomains(domain = []) {
|
||||||
|
return Promise.all(domain.map((domain) => this.unmuteDomain(domain)))
|
||||||
|
},
|
||||||
|
fetchFriends(id) {
|
||||||
|
const user = this.users.get(id)
|
||||||
|
const maxId = last(user.friendIds)
|
||||||
|
return fetchFriends({
|
||||||
|
id,
|
||||||
|
maxId,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: friends }) => {
|
||||||
|
this.addNewUsers(friends)
|
||||||
|
this.saveFriendIds({ id, friendIds: map(friends, 'id') })
|
||||||
|
return friends
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchFollowers(id) {
|
||||||
|
const user = this.users.get(id)
|
||||||
|
const maxId = last(user.followerIds)
|
||||||
|
return fetchFollowers({
|
||||||
|
id,
|
||||||
|
maxId,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: followers }) => {
|
||||||
|
this.addNewUsers(followers)
|
||||||
|
this.saveFollowerIds({ id, followerIds: map(followers, 'id') })
|
||||||
|
return followers
|
||||||
|
})
|
||||||
|
},
|
||||||
|
subscribeUser(id) {
|
||||||
|
return followUser({
|
||||||
|
id,
|
||||||
|
notify: true,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: relationship }) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
unsubscribeUser(id) {
|
||||||
|
return followUser({
|
||||||
|
id,
|
||||||
|
notify: false,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: relationship }) =>
|
||||||
|
this.updateUserRelationship([relationship]),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
registerPushNotifications() {
|
||||||
|
const token = this.currentUser.credentials
|
||||||
|
const vapidPublicKey = useInstanceStore().vapidPublicKey
|
||||||
|
const isEnabled = useMergedConfigStore().mergedConfig.webPushNotifications
|
||||||
|
const notificationVisibility =
|
||||||
|
useMergedConfigStore().mergedConfig.notificationVisibility
|
||||||
|
|
||||||
|
registerPushNotifications(
|
||||||
|
isEnabled,
|
||||||
|
vapidPublicKey,
|
||||||
|
token,
|
||||||
|
notificationVisibility,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
unregisterPushNotifications() {
|
||||||
|
const token = this.currentUser.credentials
|
||||||
|
|
||||||
|
unregisterPushNotifications(token)
|
||||||
|
},
|
||||||
|
searchUsers({ query }) {
|
||||||
|
return searchUsers({
|
||||||
|
query,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then(({ data: users }) => {
|
||||||
|
this.addNewUsers(users)
|
||||||
|
return users
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
const store = window.vuex
|
||||||
|
const oauth = useOAuthStore()
|
||||||
|
|
||||||
|
// NOTE: No need to verify the app still exists, because if it doesn't,
|
||||||
|
// the token will be invalid too
|
||||||
|
return oauth
|
||||||
|
.ensureApp()
|
||||||
|
.then((app) => {
|
||||||
|
const params = {
|
||||||
|
app,
|
||||||
|
instance: useInstanceStore().server,
|
||||||
|
token: oauth.userToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
return revokeToken(params)
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.clearCurrentUser()
|
||||||
|
store.dispatch('disconnectFromSocket')
|
||||||
|
store.dispatch('stopFetchingTimeline', 'friends')
|
||||||
|
store.dispatch('stopFetchingNotifications')
|
||||||
|
useListsStore().stopFetching()
|
||||||
|
useBookmarkFoldersStore().stopFetching()
|
||||||
|
store.dispatch('stopFetchingFollowRequests')
|
||||||
|
store.commit('clearNotifications')
|
||||||
|
store.commit('resetStatuses')
|
||||||
|
useChatsStore().resetChats()
|
||||||
|
oauth.clearToken()
|
||||||
|
Cookies.remove('__Host-pleroma_key', { path: '/' })
|
||||||
|
useInterfaceStore().setLastTimeline('public-timeline')
|
||||||
|
useInterfaceStore().setLayoutWidth(windowWidth())
|
||||||
|
useInterfaceStore().setLayoutHeight(windowHeight())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loginUser(accessToken) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const store = window.vuex
|
||||||
|
const dispatch = store.dispatch
|
||||||
|
|
||||||
|
this.loggingIn = true
|
||||||
|
|
||||||
|
verifyCredentials({
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
})
|
||||||
|
.then(({ data: user }) => {
|
||||||
|
// user.credentials = userCredentials
|
||||||
|
user.credentials = accessToken
|
||||||
|
user.blockIds = []
|
||||||
|
user.muteIds = []
|
||||||
|
user.domainMutes = []
|
||||||
|
this.setCurrentUser(user)
|
||||||
|
|
||||||
|
useSyncConfigStore()
|
||||||
|
.initSyncConfig(user)
|
||||||
|
.then(() => {
|
||||||
|
useInterfaceStore()
|
||||||
|
.applyTheme()
|
||||||
|
.catch((e) => {
|
||||||
|
console.error('Error setting theme', e)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
useUserHighlightStore().initUserHighlight(user)
|
||||||
|
this.addNewUsers([user])
|
||||||
|
|
||||||
|
useEmojiStore().fetchEmoji()
|
||||||
|
|
||||||
|
getNotificationPermission().then((permission) =>
|
||||||
|
useInterfaceStore().setNotificationPermission(permission),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Do server-side storage migrations
|
||||||
|
|
||||||
|
// Debug snippet to clean up storage and reset migrations
|
||||||
|
/*
|
||||||
|
// Reset wordfilter
|
||||||
|
Object.keys(
|
||||||
|
useSyncConfigStore().prefsStorage.simple.muteFilters
|
||||||
|
).forEach(key => {
|
||||||
|
useSyncConfigStore().unsetSimplePrefAndSave({ path: 'muteFilters.' + key, value: null })
|
||||||
|
})
|
||||||
|
|
||||||
|
// Reset flag to 0 to re-run migrations
|
||||||
|
useSyncConfigStore().setFlag({ flag: 'configMigration', value: 0 })
|
||||||
|
/**/
|
||||||
|
|
||||||
|
if (user.token) {
|
||||||
|
dispatch('setWsToken', user.token)
|
||||||
|
|
||||||
|
// Initialize the shout socket.
|
||||||
|
dispatch('initializeSocket')
|
||||||
|
}
|
||||||
|
|
||||||
|
const startPolling = () => {
|
||||||
|
// Start getting fresh posts.
|
||||||
|
dispatch('startFetchingTimeline', { timeline: 'friends' })
|
||||||
|
|
||||||
|
// Start fetching notifications
|
||||||
|
dispatch('startFetchingNotifications')
|
||||||
|
|
||||||
|
if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) {
|
||||||
|
// Start fetching chats
|
||||||
|
dispatch('startFetchingChats')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useListsStore().startFetching()
|
||||||
|
useBookmarkFoldersStore().startFetching()
|
||||||
|
|
||||||
|
if (user.locked) {
|
||||||
|
dispatch('startFetchingFollowRequests')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useMergedConfigStore().mergedConfig.useStreamingApi) {
|
||||||
|
dispatch('fetchTimeline', {
|
||||||
|
timeline: 'friends',
|
||||||
|
sinceId: null,
|
||||||
|
})
|
||||||
|
dispatch('fetchNotifications', { sinceId: null })
|
||||||
|
dispatch('enableMastoSockets', true)
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(
|
||||||
|
'Failed initializing MastoAPI Streaming socket',
|
||||||
|
error,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
dispatch('fetchChats', { latest: true })
|
||||||
|
setTimeout(
|
||||||
|
() => dispatch('setNotificationsSilence', false),
|
||||||
|
10000,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
startPolling()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start fetching things that don't need to block the UI
|
||||||
|
useAnnouncementsStore().startFetchingAnnouncements()
|
||||||
|
|
||||||
|
this.fetchMutes()
|
||||||
|
dispatch('loadDrafts')
|
||||||
|
|
||||||
|
useInterfaceStore().setLayoutWidth(windowWidth())
|
||||||
|
useInterfaceStore().setLayoutHeight(windowHeight())
|
||||||
|
|
||||||
|
// Fetch our friends
|
||||||
|
fetchFriends({ id: user.id }).then(({ data: friends }) =>
|
||||||
|
this.addNewUsers(friends),
|
||||||
|
)
|
||||||
|
this.loggingIn = false
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error)
|
||||||
|
|
||||||
|
// Authentication failed
|
||||||
|
this.loggingIn = false
|
||||||
|
|
||||||
|
// remove authentication token on client/authentication errors
|
||||||
|
if ([400, 401, 403, 422].includes(error.statusCode)) {
|
||||||
|
useOAuthStore().clearToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loggingIn = false
|
||||||
|
if (error.tatusCode === 401) {
|
||||||
|
throw new Error('Wrong username or password', error)
|
||||||
|
} else {
|
||||||
|
throw new Error('An error occurred, please try again', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue