From bf009440ffcca59642ed67dbf64319897312f8ab Mon Sep 17 00:00:00 2001 From: Kasper Seweryn Date: Mon, 2 May 2022 09:36:01 +0200 Subject: [PATCH] Migrate attachment input to new v-model It also automatically cleans up attachments that users uploaded and decided not to use --- front/src/components/audio/ChannelForm.vue | 1 - front/src/components/auth/Settings.vue | 8 +- .../channels/UploadMetadataForm.vue | 1 - .../src/components/common/AttachmentInput.vue | 167 ++++++++++-------- front/src/init/axios.ts | 37 ++-- front/src/types.ts | 16 ++ 6 files changed, 131 insertions(+), 99 deletions(-) diff --git a/front/src/components/audio/ChannelForm.vue b/front/src/components/audio/ChannelForm.vue index 6849d1861..ae8d3a8a2 100644 --- a/front/src/components/audio/ChannelForm.vue +++ b/front/src/components/audio/ChannelForm.vue @@ -95,7 +95,6 @@
diff --git a/front/src/components/auth/Settings.vue b/front/src/components/auth/Settings.vue index 7b07eb5ce..d58bf2118 100644 --- a/front/src/components/auth/Settings.vue +++ b/front/src/components/auth/Settings.vue @@ -109,12 +109,10 @@
- {{ }} @@ -739,7 +737,7 @@ export default { // properties that will be used in it old_password: '', new_password: '', - avatar: { ...(this.$store.state.auth.profile.avatar || { uuid: null }) }, + avatar: { ...(this.$store.state.auth.profile?.avatar ?? { uuid: null }) }, passwordError: '', password: '', isLoading: false, diff --git a/front/src/components/channels/UploadMetadataForm.vue b/front/src/components/channels/UploadMetadataForm.vue index 17d676d8d..27832d8be 100644 --- a/front/src/components/channels/UploadMetadataForm.vue +++ b/front/src/components/channels/UploadMetadataForm.vue @@ -11,7 +11,6 @@ diff --git a/front/src/components/common/AttachmentInput.vue b/front/src/components/common/AttachmentInput.vue index 64931b990..ffc1e53aa 100644 --- a/front/src/components/common/AttachmentInput.vue +++ b/front/src/components/common/AttachmentInput.vue @@ -1,3 +1,93 @@ + + - diff --git a/front/src/init/axios.ts b/front/src/init/axios.ts index ac6b8cb83..e390e7731 100644 --- a/front/src/init/axios.ts +++ b/front/src/init/axios.ts @@ -1,4 +1,4 @@ -import { InitModule } from '~/types' +import { BackendError, InitModule, RateLimitStatus } from '~/types' import createAuthRefreshInterceptor from 'axios-auth-refresh' import axios, { AxiosError } from 'axios' @@ -28,36 +28,35 @@ export const install: InitModule = ({ store, router }) => { // Add a response interceptor axios.interceptors.response.use(function (response) { return response - }, async (error) => { + }, async (error: BackendError) => { error.backendErrors = [] - if (store.state.auth.authenticated && !store.state.auth.oauth.accessToken && error.response.status === 401) { + if (store.state.auth.authenticated && !store.state.auth.oauth.accessToken && error.response?.status === 401) { store.commit('auth/authenticated', false) logger.warn('Received 401 response from API, redirecting to login form', router.currentRoute.value.fullPath) await router.push({ name: 'login', query: { next: router.currentRoute.value.fullPath } }) } - if (error.response.status === 404) { + if (error.response?.status === 404) { error.backendErrors.push('Resource not found') - const message = error.response.data + const message = error.response?.data store.commit('ui/addMessage', { content: message, class: 'error' }) - } else if (error.response.status === 403) { + } else if (error.response?.status === 403) { error.backendErrors.push('Permission denied') - } else if (error.response.status === 429) { + } else if (error.response?.status === 429) { let message - const rateLimitStatus = { - limit: error.response.headers['x-ratelimit-limit'], - scope: error.response.headers['x-ratelimit-scope'], - remaining: error.response.headers['x-ratelimit-remaining'], - duration: error.response.headers['x-ratelimit-duration'], - availableSeconds: error.response.headers['retry-after'], - reset: error.response.headers['x-ratelimit-reset'], - resetSeconds: error.response.headers['x-ratelimit-resetseconds'] + const rateLimitStatus: RateLimitStatus = { + limit: error.response?.headers['x-ratelimit-limit'], + scope: error.response?.headers['x-ratelimit-scope'], + remaining: error.response?.headers['x-ratelimit-remaining'], + duration: error.response?.headers['x-ratelimit-duration'], + availableSeconds: parseInt(error.response?.headers['retry-after'] ?? 60), + reset: error.response?.headers['x-ratelimit-reset'], + resetSeconds: error.response?.headers['x-ratelimit-resetseconds'] } if (rateLimitStatus.availableSeconds) { - rateLimitStatus.availableSeconds = parseInt(rateLimitStatus.availableSeconds) const tryAgain = moment().add(rateLimitStatus.availableSeconds, 's').toNow(true) message = $pgettext('*/Error/Paragraph', 'You sent too many requests and have been rate limited, please try again in %{ delay }') message = $gettext(message, { delay: tryAgain }) @@ -71,10 +70,10 @@ export const install: InitModule = ({ store, router }) => { class: 'error' }) logger.error('This client is rate-limited!', rateLimitStatus) - } else if (error.response.status === 500) { + } else if (error.response?.status === 500) { error.backendErrors.push('A server error occurred') - } else if (error.response.data) { - if (error.response.data.detail) { + } else if (error.response?.data) { + if (error.response?.data.detail) { error.backendErrors.push(error.response.data.detail) } else { error.rawPayload = error.response.data diff --git a/front/src/types.ts b/front/src/types.ts index 679ba0456..967f0699b 100644 --- a/front/src/types.ts +++ b/front/src/types.ts @@ -1,6 +1,7 @@ import type { App } from 'vue' import type { Store } from 'vuex' import { Router } from 'vue-router' +import {AxiosError} from "axios"; declare global { interface Window { @@ -47,6 +48,21 @@ export interface APIErrorResponse { [key: string]: APIErrorResponse | string[] } +export interface BackendError extends AxiosError { + backendErrors: string[] + rawPayload?: object +} + +export interface RateLimitStatus { + limit: string + scope: string + remaining: string + duration: string + availableSeconds: number + reset: string + resetSeconds: string +} + // WebSocket stuff export interface PendingReviewEditsWSEvent { pending_review_count: number