Page MenuHomePhorge

No OneTemporary

Size
33 KB
Referenced Files
None
Subscribers
None
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f5a93057b..6dcbc7da58 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,35 +1,37 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Changed
+- Captcha now resets on failed registrations
- Notifications column now cleans itself up to optimize performance when tab is left open for a long time
### Fixed
- Single notifications left unread when hitting read on another device/tab
+- Registration fixed
## [1.1.8] - 2020-01-10
### Added
- Icons in nav panel
- Private mode support
- Support for 'Move' type notifications
- Pleroma AMOLED dark theme
### Changed
- 403 messaging
### Fixed
- Deactivation of remote accounts from frontend
## [1.1.7 and earlier] - 2019-12-14
### Added
- Ability to hide/show repeats from user
- User profile button clutter organized into a menu
- Emoji picker
- Started changelog anew
- Ability to change user's email
- About page
- Added remote user redirect
### Changed
- changed the way fading effects for user profile/long statuses works, now uses css-mask instead of gradient background hacks which weren't exactly compatible with semi-transparent themes
### Fixed
- improved hotkey behavior on autocomplete popup
diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js
index 57f3caf015..ace8cc7ce8 100644
--- a/src/components/registration/registration.js
+++ b/src/components/registration/registration.js
@@ -1,76 +1,77 @@
import { validationMixin } from 'vuelidate'
import { required, sameAs } from 'vuelidate/lib/validators'
import { mapActions, mapState } from 'vuex'
const registration = {
mixins: [validationMixin],
data: () => ({
user: {
email: '',
fullname: '',
username: '',
password: '',
confirm: ''
},
captcha: {}
}),
validations: {
user: {
email: { required },
username: { required },
fullname: { required },
password: { required },
confirm: {
required,
sameAsPassword: sameAs('password')
}
}
},
created () {
if ((!this.registrationOpen && !this.token) || this.signedIn) {
this.$router.push({ name: 'root' })
}
this.setCaptcha()
},
computed: {
token () { return this.$route.params.token },
bioPlaceholder () {
return this.$t('registration.bio_placeholder').replace(/\s*\n\s*/g, ' \n')
},
...mapState({
registrationOpen: (state) => state.instance.registrationOpen,
signedIn: (state) => !!state.users.currentUser,
isPending: (state) => state.users.signUpPending,
serverValidationErrors: (state) => state.users.signUpErrors,
termsOfService: (state) => state.instance.tos
})
},
methods: {
...mapActions(['signUp', 'getCaptcha']),
async submit () {
this.user.nickname = this.user.username
this.user.token = this.token
this.user.captcha_solution = this.captcha.solution
this.user.captcha_token = this.captcha.token
this.user.captcha_answer_data = this.captcha.answer_data
this.$v.$touch()
if (!this.$v.$invalid) {
try {
await this.signUp(this.user)
this.$router.push({ name: 'friends' })
} catch (error) {
- console.warn('Registration failed: ' + error)
+ console.warn('Registration failed: ', error)
+ this.setCaptcha()
}
}
},
setCaptcha () {
this.getCaptcha().then(cpt => { this.captcha = cpt })
}
}
}
export default registration
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index 222b67a87d..fdbda0077a 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -1,337 +1,337 @@
<template>
<div class="settings panel panel-default">
<div class="panel-heading">
{{ $t('registration.registration') }}
</div>
<div class="panel-body">
<form
class="registration-form"
@submit.prevent="submit(user)"
>
<div class="container">
<div class="text-fields">
<div
class="form-group"
:class="{ 'form-group--error': $v.user.username.$error }"
>
<label
class="form--label"
for="sign-up-username"
>{{ $t('login.username') }}</label>
<input
id="sign-up-username"
v-model.trim="$v.user.username.$model"
:disabled="isPending"
class="form-control"
:placeholder="$t('registration.username_placeholder')"
>
</div>
<div
v-if="$v.user.username.$dirty"
class="form-error"
>
<ul>
<li v-if="!$v.user.username.required">
<span>{{ $t('registration.validations.username_required') }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': $v.user.fullname.$error }"
>
<label
class="form--label"
for="sign-up-fullname"
>{{ $t('registration.fullname') }}</label>
<input
id="sign-up-fullname"
v-model.trim="$v.user.fullname.$model"
:disabled="isPending"
class="form-control"
:placeholder="$t('registration.fullname_placeholder')"
>
</div>
<div
v-if="$v.user.fullname.$dirty"
class="form-error"
>
<ul>
<li v-if="!$v.user.fullname.required">
<span>{{ $t('registration.validations.fullname_required') }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': $v.user.email.$error }"
>
<label
class="form--label"
for="email"
>{{ $t('registration.email') }}</label>
<input
id="email"
v-model="$v.user.email.$model"
:disabled="isPending"
class="form-control"
type="email"
>
</div>
<div
v-if="$v.user.email.$dirty"
class="form-error"
>
<ul>
<li v-if="!$v.user.email.required">
<span>{{ $t('registration.validations.email_required') }}</span>
</li>
</ul>
</div>
<div class="form-group">
<label
class="form--label"
for="bio"
>{{ $t('registration.bio') }} ({{ $t('general.optional') }})</label>
<textarea
id="bio"
v-model="user.bio"
:disabled="isPending"
class="form-control"
:placeholder="bioPlaceholder"
/>
</div>
<div
class="form-group"
:class="{ 'form-group--error': $v.user.password.$error }"
>
<label
class="form--label"
for="sign-up-password"
>{{ $t('login.password') }}</label>
<input
id="sign-up-password"
v-model="user.password"
:disabled="isPending"
class="form-control"
type="password"
>
</div>
<div
v-if="$v.user.password.$dirty"
class="form-error"
>
<ul>
<li v-if="!$v.user.password.required">
<span>{{ $t('registration.validations.password_required') }}</span>
</li>
</ul>
</div>
<div
class="form-group"
:class="{ 'form-group--error': $v.user.confirm.$error }"
>
<label
class="form--label"
for="sign-up-password-confirmation"
>{{ $t('registration.password_confirm') }}</label>
<input
id="sign-up-password-confirmation"
v-model="user.confirm"
:disabled="isPending"
class="form-control"
type="password"
>
</div>
<div
v-if="$v.user.confirm.$dirty"
class="form-error"
>
<ul>
<li v-if="!$v.user.confirm.required">
<span>{{ $t('registration.validations.password_confirmation_required') }}</span>
</li>
<li v-if="!$v.user.confirm.sameAsPassword">
<span>{{ $t('registration.validations.password_confirmation_match') }}</span>
</li>
</ul>
</div>
<div
v-if="captcha.type != 'none'"
id="captcha-group"
class="form-group"
>
<label
class="form--label"
for="captcha-label"
- >{{ $t('captcha') }}</label>
+ >{{ $t('registration.captcha') }}</label>
<template v-if="['kocaptcha', 'native'].includes(captcha.type)">
<img
:src="captcha.url"
@click="setCaptcha"
>
<sub>{{ $t('registration.new_captcha') }}</sub>
<input
id="captcha-answer"
v-model="captcha.solution"
:disabled="isPending"
class="form-control"
type="text"
autocomplete="off"
>
</template>
</div>
<div
v-if="token"
class="form-group"
>
<label for="token">{{ $t('registration.token') }}</label>
<input
id="token"
v-model="token"
disabled="true"
class="form-control"
type="text"
>
</div>
<div class="form-group">
<button
:disabled="isPending"
type="submit"
class="btn btn-default"
>
{{ $t('general.submit') }}
</button>
</div>
</div>
<!-- eslint-disable vue/no-v-html -->
<div
class="terms-of-service"
v-html="termsOfService"
/>
<!-- eslint-enable vue/no-v-html -->
</div>
<div
v-if="serverValidationErrors.length"
class="form-group"
>
<div class="alert error">
<span
v-for="error in serverValidationErrors"
:key="error"
>{{ error }}</span>
</div>
</div>
</form>
</div>
</div>
</template>
<script src="./registration.js"></script>
<style lang="scss">
@import '../../_variables.scss';
$validations-cRed: #f04124;
.registration-form {
display: flex;
flex-direction: column;
margin: 0.6em;
.container {
display: flex;
flex-direction: row;
//margin-bottom: 1em;
}
.terms-of-service {
flex: 0 1 50%;
margin: 0.8em;
}
.text-fields {
margin-top: 0.6em;
flex: 1 0;
display: flex;
flex-direction: column;
}
textarea {
min-height: 100px;
resize: vertical;
}
.form-group {
display: flex;
flex-direction: column;
padding: 0.3em 0.0em 0.3em;
line-height:24px;
margin-bottom: 1em;
}
.form-group--error {
animation-name: shakeError;
animation-duration: .6s;
animation-timing-function: ease-in-out;
}
.form-group--error .form--label {
color: $validations-cRed;
color: var(--cRed, $validations-cRed);
}
.form-error {
margin-top: -0.7em;
text-align: left;
span {
font-size: 12px;
}
}
.form-error ul {
list-style: none;
padding: 0 0 0 5px;
margin-top: 0;
li::before {
content: "• ";
}
}
form textarea {
line-height:16px;
resize: vertical;
}
.captcha {
max-width: 350px;
margin-bottom: 0.4em;
}
.btn {
margin-top: 0.6em;
height: 28px;
}
.error {
text-align: center;
}
}
@media all and (max-width: 800px) {
.registration-form .container {
flex-direction: column-reverse;
}
}
</style>
diff --git a/src/modules/users.js b/src/modules/users.js
index 84fa025552..b9ed0efab3 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -1,527 +1,529 @@
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import oauthApi from '../services/new_api/oauth.js'
import { compact, map, each, merge, last, concat, uniq } from 'lodash'
import { set } from 'vue'
import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
// TODO: Unify with mergeOrAdd in statuses.js
export const mergeOrAdd = (arr, obj, item) => {
if (!item) { return false }
const oldItem = obj[item.id]
if (oldItem) {
// We already have this, so only merge the new info.
merge(oldItem, item)
return { item: oldItem, new: false }
} else {
// This is a new item, prepare it
arr.push(item)
set(obj, item.id, item)
if (item.screen_name && !item.screen_name.includes('@')) {
set(obj, item.screen_name.toLowerCase(), item)
}
return { item, new: true }
}
}
const getNotificationPermission = () => {
const Notification = window.Notification
if (!Notification) return Promise.resolve(null)
if (Notification.permission === 'default') return Notification.requestPermission()
return Promise.resolve(Notification.permission)
}
const blockUser = (store, id) => {
return store.rootState.api.backendInteractor.blockUser({ id })
.then((relationship) => {
store.commit('updateUserRelationship', [relationship])
store.commit('addBlockId', id)
store.commit('removeStatus', { timeline: 'friends', userId: id })
store.commit('removeStatus', { timeline: 'public', userId: id })
store.commit('removeStatus', { timeline: 'publicAndExternal', userId: id })
})
}
const unblockUser = (store, id) => {
return store.rootState.api.backendInteractor.unblockUser({ id })
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
}
const muteUser = (store, id) => {
return store.rootState.api.backendInteractor.muteUser({ id })
.then((relationship) => {
store.commit('updateUserRelationship', [relationship])
store.commit('addMuteId', id)
})
}
const unmuteUser = (store, id) => {
return store.rootState.api.backendInteractor.unmuteUser({ id })
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
}
const hideReblogs = (store, userId) => {
return store.rootState.api.backendInteractor.followUser({ id: userId, reblogs: false })
.then((relationship) => {
store.commit('updateUserRelationship', [relationship])
})
}
const showReblogs = (store, userId) => {
return store.rootState.api.backendInteractor.followUser({ id: userId, reblogs: true })
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
}
export const mutations = {
setMuted (state, { user: { id }, muted }) {
const user = state.usersObject[id]
set(user, 'muted', muted)
},
tagUser (state, { user: { id }, tag }) {
const user = state.usersObject[id]
const tags = user.tags || []
const newTags = tags.concat([tag])
set(user, 'tags', newTags)
},
untagUser (state, { user: { id }, tag }) {
const user = state.usersObject[id]
const tags = user.tags || []
const newTags = tags.filter(t => t !== tag)
set(user, 'tags', newTags)
},
updateRight (state, { user: { id }, right, value }) {
const user = state.usersObject[id]
let newRights = user.rights
newRights[right] = value
set(user, 'rights', newRights)
},
updateActivationStatus (state, { user: { id }, deactivated }) {
const user = state.usersObject[id]
set(user, 'deactivated', deactivated)
},
setCurrentUser (state, user) {
state.lastLoginName = user.screen_name
state.currentUser = merge(state.currentUser || {}, user)
},
clearCurrentUser (state) {
state.currentUser = false
state.lastLoginName = false
},
beginLogin (state) {
state.loggingIn = true
},
endLogin (state) {
state.loggingIn = false
},
saveFriendIds (state, { id, friendIds }) {
const user = state.usersObject[id]
user.friendIds = uniq(concat(user.friendIds, friendIds))
},
saveFollowerIds (state, { id, followerIds }) {
const user = state.usersObject[id]
user.followerIds = uniq(concat(user.followerIds, followerIds))
},
// Because frontend doesn't have a reason to keep these stuff in memory
// outside of viewing someones user profile.
clearFriends (state, userId) {
const user = state.usersObject[userId]
if (user) {
set(user, 'friendIds', [])
}
},
clearFollowers (state, userId) {
const user = state.usersObject[userId]
if (user) {
set(user, 'followerIds', [])
}
},
addNewUsers (state, users) {
each(users, (user) => mergeOrAdd(state.users, state.usersObject, user))
},
updateUserRelationship (state, relationships) {
relationships.forEach((relationship) => {
const user = state.usersObject[relationship.id]
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) {
state.currentUser.blockIds = blockIds
},
addBlockId (state, blockId) {
if (state.currentUser.blockIds.indexOf(blockId) === -1) {
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) {
state.currentUser.muteIds = muteIds
},
addMuteId (state, muteId) {
if (state.currentUser.muteIds.indexOf(muteId) === -1) {
state.currentUser.muteIds.push(muteId)
}
},
setPinnedToUser (state, status) {
const user = state.usersObject[status.user.id]
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 (state, status) {
status.user = state.usersObject[status.user.id]
},
setUserForNotification (state, notification) {
if (notification.type !== 'follow') {
notification.action.user = state.usersObject[notification.action.user.id]
}
notification.from_profile = state.usersObject[notification.from_profile.id]
},
setColor (state, { user: { id }, highlighted }) {
const user = state.usersObject[id]
set(user, 'highlight', highlighted)
},
signUpPending (state) {
state.signUpPending = true
state.signUpErrors = []
},
signUpSuccess (state) {
state.signUpPending = false
},
signUpFailure (state, errors) {
state.signUpPending = false
state.signUpErrors = errors
}
}
export const getters = {
findUser: state => query => {
const result = state.usersObject[query]
// In case it's a screen_name, we can try searching case-insensitive
if (!result && typeof query === 'string') {
return state.usersObject[query.toLowerCase()]
}
return result
}
}
export const defaultState = {
loggingIn: false,
lastLoginName: false,
currentUser: false,
users: [],
usersObject: {},
signUpPending: false,
signUpErrors: []
}
const users = {
state: defaultState,
mutations,
getters,
actions: {
fetchUser (store, id) {
return store.rootState.api.backendInteractor.fetchUser({ id })
.then((user) => {
store.commit('addNewUsers', [user])
return user
})
},
fetchUserRelationship (store, id) {
if (store.state.currentUser) {
store.rootState.api.backendInteractor.fetchUserRelationship({ id })
.then((relationships) => store.commit('updateUserRelationship', relationships))
}
},
fetchBlocks (store) {
return store.rootState.api.backendInteractor.fetchBlocks()
.then((blocks) => {
store.commit('saveBlockIds', map(blocks, 'id'))
store.commit('updateBlocks', blocks)
return blocks
})
},
blockUser (store, id) {
return blockUser(store, id)
},
unblockUser (store, id) {
return unblockUser(store, id)
},
blockUsers (store, ids = []) {
return Promise.all(ids.map(id => blockUser(store, id)))
},
unblockUsers (store, ids = []) {
return Promise.all(ids.map(id => unblockUser(store, id)))
},
fetchMutes (store) {
return store.rootState.api.backendInteractor.fetchMutes()
.then((mutes) => {
store.commit('updateMutes', mutes)
store.commit('saveMuteIds', map(mutes, 'id'))
return mutes
})
},
muteUser (store, id) {
return muteUser(store, id)
},
unmuteUser (store, id) {
return unmuteUser(store, id)
},
hideReblogs (store, id) {
return hideReblogs(store, id)
},
showReblogs (store, id) {
return showReblogs(store, id)
},
muteUsers (store, ids = []) {
return Promise.all(ids.map(id => muteUser(store, id)))
},
unmuteUsers (store, ids = []) {
return Promise.all(ids.map(id => unmuteUser(store, id)))
},
fetchFriends ({ rootState, commit }, id) {
const user = rootState.users.usersObject[id]
const maxId = last(user.friendIds)
return rootState.api.backendInteractor.fetchFriends({ id, maxId })
.then((friends) => {
commit('addNewUsers', friends)
commit('saveFriendIds', { id, friendIds: map(friends, 'id') })
return friends
})
},
fetchFollowers ({ rootState, commit }, id) {
const user = rootState.users.usersObject[id]
const maxId = last(user.followerIds)
return rootState.api.backendInteractor.fetchFollowers({ id, maxId })
.then((followers) => {
commit('addNewUsers', followers)
commit('saveFollowerIds', { id, followerIds: map(followers, 'id') })
return followers
})
},
clearFriends ({ commit }, userId) {
commit('clearFriends', userId)
},
clearFollowers ({ commit }, userId) {
commit('clearFollowers', userId)
},
subscribeUser ({ rootState, commit }, id) {
return rootState.api.backendInteractor.subscribeUser({ id })
.then((relationship) => commit('updateUserRelationship', [relationship]))
},
unsubscribeUser ({ rootState, commit }, id) {
return rootState.api.backendInteractor.unsubscribeUser({ id })
.then((relationship) => commit('updateUserRelationship', [relationship]))
},
toggleActivationStatus ({ rootState, commit }, user) {
const api = user.deactivated ? rootState.api.backendInteractor.activateUser : rootState.api.backendInteractor.deactivateUser
api(user)
.then(({ deactivated }) => commit('updateActivationStatus', { user, deactivated }))
},
registerPushNotifications (store) {
const token = store.state.currentUser.credentials
const vapidPublicKey = store.rootState.instance.vapidPublicKey
const isEnabled = store.rootState.config.webPushNotifications
const notificationVisibility = store.rootState.config.notificationVisibility
registerPushNotifications(isEnabled, vapidPublicKey, token, notificationVisibility)
},
unregisterPushNotifications (store) {
const token = store.state.currentUser.credentials
unregisterPushNotifications(token)
},
addNewUsers ({ commit }, users) {
commit('addNewUsers', users)
},
addNewStatuses (store, { statuses }) {
const users = map(statuses, 'user')
const retweetedUsers = compact(map(statuses, 'retweeted_status.user'))
store.commit('addNewUsers', users)
store.commit('addNewUsers', retweetedUsers)
each(statuses, (status) => {
// Reconnect users to statuses
store.commit('setUserForStatus', status)
// Set pinned statuses to user
store.commit('setPinnedToUser', status)
})
each(compact(map(statuses, 'retweeted_status')), (status) => {
// Reconnect users to retweets
store.commit('setUserForStatus', status)
// Set pinned retweets to user
store.commit('setPinnedToUser', status)
})
},
addNewNotifications (store, { notifications }) {
const users = map(notifications, 'from_profile')
const targetUsers = map(notifications, 'target')
const notificationIds = notifications.map(_ => _.id)
store.commit('addNewUsers', users)
store.commit('addNewUsers', targetUsers)
const notificationsObject = store.rootState.statuses.notifications.idStore
const relevantNotifications = Object.entries(notificationsObject)
.filter(([k, val]) => notificationIds.includes(k))
.map(([k, val]) => val)
// Reconnect users to notifications
each(relevantNotifications, (notification) => {
store.commit('setUserForNotification', notification)
})
},
searchUsers (store, query) {
return store.rootState.api.backendInteractor.searchUsers({ query })
.then((users) => {
store.commit('addNewUsers', users)
return users
})
},
async signUp (store, userInfo) {
store.commit('signUpPending')
let rootState = store.rootState
try {
- let data = await rootState.api.backendInteractor.register({ ...userInfo })
+ let data = await rootState.api.backendInteractor.register(
+ { params: { ...userInfo } }
+ )
store.commit('signUpSuccess')
store.commit('setToken', data.access_token)
store.dispatch('loginUser', data.access_token)
} catch (e) {
let errors = e.message
store.commit('signUpFailure', errors)
throw e
}
},
async getCaptcha (store) {
return store.rootState.api.backendInteractor.getCaptcha()
},
logout (store) {
const { oauth, instance } = store.rootState
const data = {
...oauth,
commit: store.commit,
instance: instance.server
}
return oauthApi.getOrCreateApp(data)
.then((app) => {
const params = {
app,
instance: data.instance,
token: oauth.userToken
}
return oauthApi.revokeToken(params)
})
.then(() => {
store.commit('clearCurrentUser')
store.dispatch('disconnectFromSocket')
store.commit('clearToken')
store.dispatch('stopFetchingTimeline', 'friends')
store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
store.dispatch('stopFetchingNotifications')
store.dispatch('stopFetchingFollowRequests')
store.commit('clearNotifications')
store.commit('resetStatuses')
})
},
loginUser (store, accessToken) {
return new Promise((resolve, reject) => {
const commit = store.commit
commit('beginLogin')
store.rootState.api.backendInteractor.verifyCredentials(accessToken)
.then((data) => {
if (!data.error) {
const user = data
// user.credentials = userCredentials
user.credentials = accessToken
user.blockIds = []
user.muteIds = []
commit('setCurrentUser', user)
commit('addNewUsers', [user])
store.dispatch('fetchEmoji')
getNotificationPermission()
.then(permission => commit('setNotificationPermission', permission))
// Set our new backend interactor
commit('setBackendInteractor', backendInteractorService(accessToken))
if (user.token) {
store.dispatch('setWsToken', user.token)
// Initialize the chat socket.
store.dispatch('initializeSocket')
}
const startPolling = () => {
// Start getting fresh posts.
store.dispatch('startFetchingTimeline', { timeline: 'friends' })
// Start fetching notifications
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
store.dispatch('fetchMutes')
// Fetch our friends
store.rootState.api.backendInteractor.fetchFriends({ id: user.id })
.then((friends) => commit('addNewUsers', friends))
} else {
const response = data.error
// Authentication failed
commit('endLogin')
if (response.status === 401) {
reject(new Error('Wrong username or password'))
} else {
reject(new Error('An error occurred, please try again'))
}
}
commit('endLogin')
resolve()
})
.catch((error) => {
console.log(error)
commit('endLogin')
reject(new Error('Failed to connect to server, try again'))
})
})
}
}
}
export default users
diff --git a/src/services/errors/errors.js b/src/services/errors/errors.js
index 590552da10..d4cf913286 100644
--- a/src/services/errors/errors.js
+++ b/src/services/errors/errors.js
@@ -1,49 +1,55 @@
import { humanizeErrors } from '../../modules/errors'
export function StatusCodeError (statusCode, body, options, response) {
this.name = 'StatusCodeError'
this.statusCode = statusCode
this.message = statusCode + ' - ' + (JSON && JSON.stringify ? JSON.stringify(body) : body)
this.error = body // legacy attribute
this.options = options
this.response = response
if (Error.captureStackTrace) { // required for non-V8 environments
Error.captureStackTrace(this)
}
}
StatusCodeError.prototype = Object.create(Error.prototype)
StatusCodeError.prototype.constructor = StatusCodeError
export class RegistrationError extends Error {
constructor (error) {
super()
if (Error.captureStackTrace) {
Error.captureStackTrace(this)
}
try {
// the error is probably a JSON object with a single key, "errors", whose value is another JSON object containing the real errors
if (typeof error === 'string') {
error = JSON.parse(error)
if (error.hasOwnProperty('error')) {
error = JSON.parse(error.error)
}
}
if (typeof error === 'object') {
+ const errorContents = JSON.parse(error.error)
+ // keys will have the property that has the error, for example 'ap_id',
+ // 'email' or 'captcha', the value will be an array of its error
+ // like "ap_id": ["has been taken"] or "captcha": ["Invalid CAPTCHA"]
+
// replace ap_id with username
- if (error.ap_id) {
- error.username = error.ap_id
- delete error.ap_id
+ if (errorContents.ap_id) {
+ errorContents.username = errorContents.ap_id
+ delete errorContents.ap_id
}
- this.message = humanizeErrors(error)
+
+ this.message = humanizeErrors(errorContents)
} else {
this.message = error
}
} catch (e) {
// can't parse it, so just treat it like a string
this.message = error
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 9, 8:45 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1784590
Default Alt Text
(33 KB)

Event Timeline