aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
authorRigel Kent <sendmemail@rigelk.eu>2020-12-08 21:16:10 +0100
committerGitHub <noreply@github.com>2020-12-08 21:16:10 +0100
commitf2eb23cd87cf32b8fe545178143b5f49e06a58da (patch)
treeaf7d59945af70e28fd85047e2c688c59a908f548 /client
parentc977fd3ec931c059111ddb2b8d6ddbb20b6b99a1 (diff)
downloadPeerTube-f2eb23cd87cf32b8fe545178143b5f49e06a58da.tar.gz
PeerTube-f2eb23cd87cf32b8fe545178143b5f49e06a58da.tar.zst
PeerTube-f2eb23cd87cf32b8fe545178143b5f49e06a58da.zip
emit more specific status codes on video upload (#3423)
- reduce http status codes list to potentially useful codes - convert more codes to typed ones - factorize html generator for error responses
Diffstat (limited to 'client')
-rw-r--r--client/src/app/+about/about-instance/contact-admin-modal.component.ts3
-rw-r--r--client/src/app/+accounts/accounts.component.ts6
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts3
-rw-r--r--client/src/app/+video-channels/video-channels.component.ts6
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts22
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.ts24
-rw-r--r--client/src/app/core/auth/auth.service.ts3
-rw-r--r--client/src/app/core/rest/rest-extractor.service.ts9
-rw-r--r--client/src/standalone/videos/embed.ts13
9 files changed, 63 insertions, 26 deletions
diff --git a/client/src/app/+about/about-instance/contact-admin-modal.component.ts b/client/src/app/+about/about-instance/contact-admin-modal.component.ts
index 11e442f6b..ac2a6c980 100644
--- a/client/src/app/+about/about-instance/contact-admin-modal.component.ts
+++ b/client/src/app/+about/about-instance/contact-admin-modal.component.ts
@@ -10,6 +10,7 @@ import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
10import { InstanceService } from '@app/shared/shared-instance' 10import { InstanceService } from '@app/shared/shared-instance'
11import { NgbModal } from '@ng-bootstrap/ng-bootstrap' 11import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
12import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' 12import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
13import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
13import { ServerConfig } from '@shared/models' 14import { ServerConfig } from '@shared/models'
14 15
15@Component({ 16@Component({
@@ -78,7 +79,7 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
78 }, 79 },
79 80
80 err => { 81 err => {
81 this.error = err.status === 403 82 this.error = err.status === HttpStatusCode.FORBIDDEN_403
82 ? $localize`You already sent this form recently` 83 ? $localize`You already sent this form recently`
83 : err.message 84 : err.message
84 } 85 }
diff --git a/client/src/app/+accounts/accounts.component.ts b/client/src/app/+accounts/accounts.component.ts
index dbc7c8887..4820eaf32 100644
--- a/client/src/app/+accounts/accounts.component.ts
+++ b/client/src/app/+accounts/accounts.component.ts
@@ -6,6 +6,7 @@ import { AuthService, Notifier, RedirectService, RestExtractor, ScreenService, U
6import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main' 6import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
7import { AccountReportComponent } from '@app/shared/shared-moderation' 7import { AccountReportComponent } from '@app/shared/shared-moderation'
8import { User, UserRight } from '@shared/models' 8import { User, UserRight } from '@shared/models'
9import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
9 10
10@Component({ 11@Component({
11 templateUrl: './accounts.component.html', 12 templateUrl: './accounts.component.html',
@@ -47,7 +48,10 @@ export class AccountsComponent implements OnInit, OnDestroy {
47 switchMap(accountId => this.accountService.getAccount(accountId)), 48 switchMap(accountId => this.accountService.getAccount(accountId)),
48 tap(account => this.onAccount(account)), 49 tap(account => this.onAccount(account)),
49 switchMap(account => this.videoChannelService.listAccountVideoChannels(account)), 50 switchMap(account => this.videoChannelService.listAccountVideoChannels(account)),
50 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])) 51 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [
52 HttpStatusCode.BAD_REQUEST_400,
53 HttpStatusCode.NOT_FOUND_404
54 ]))
51 ) 55 )
52 .subscribe( 56 .subscribe(
53 videoChannels => this.videoChannels = videoChannels.data, 57 videoChannels => this.videoChannels = videoChannels.data,
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts
index 1d0cbf246..a625493de 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts
@@ -10,6 +10,7 @@ import {
10import { FormValidatorService } from '@app/shared/shared-forms' 10import { FormValidatorService } from '@app/shared/shared-forms'
11import { VideoChannelService } from '@app/shared/shared-main' 11import { VideoChannelService } from '@app/shared/shared-main'
12import { VideoChannelCreate } from '@shared/models' 12import { VideoChannelCreate } from '@shared/models'
13import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
13import { MyVideoChannelEdit } from './my-video-channel-edit' 14import { MyVideoChannelEdit } from './my-video-channel-edit'
14 15
15@Component({ 16@Component({
@@ -58,7 +59,7 @@ export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements
58 }, 59 },
59 60
60 err => { 61 err => {
61 if (err.status === 409) { 62 if (err.status === HttpStatusCode.CONFLICT_409) {
62 this.error = $localize`This name already exists on this instance.` 63 this.error = $localize`This name already exists on this instance.`
63 return 64 return
64 } 65 }
diff --git a/client/src/app/+video-channels/video-channels.component.ts b/client/src/app/+video-channels/video-channels.component.ts
index ea8bda1cf..d2fd265c4 100644
--- a/client/src/app/+video-channels/video-channels.component.ts
+++ b/client/src/app/+video-channels/video-channels.component.ts
@@ -6,6 +6,7 @@ import { ActivatedRoute } from '@angular/router'
6import { AuthService, Notifier, RestExtractor, ScreenService } from '@app/core' 6import { AuthService, Notifier, RestExtractor, ScreenService } from '@app/core'
7import { ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main' 7import { ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
8import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' 8import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
9import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
9 10
10@Component({ 11@Component({
11 templateUrl: './video-channels.component.html', 12 templateUrl: './video-channels.component.html',
@@ -37,7 +38,10 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
37 map(params => params[ 'videoChannelName' ]), 38 map(params => params[ 'videoChannelName' ]),
38 distinctUntilChanged(), 39 distinctUntilChanged(),
39 switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)), 40 switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)),
40 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])) 41 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [
42 HttpStatusCode.BAD_REQUEST_400,
43 HttpStatusCode.NOT_FOUND_404
44 ]))
41 ) 45 )
42 .subscribe(videoChannel => { 46 .subscribe(videoChannel => {
43 this.videoChannel = videoChannel 47 this.videoChannel = videoChannel
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
index bee3679f7..cafb030b9 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
@@ -9,6 +9,7 @@ import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/sh
9import { LoadingBarService } from '@ngx-loading-bar/core' 9import { LoadingBarService } from '@ngx-loading-bar/core'
10import { VideoPrivacy } from '@shared/models' 10import { VideoPrivacy } from '@shared/models'
11import { VideoSend } from './video-send' 11import { VideoSend } from './video-send'
12import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
12 13
13@Component({ 14@Component({
14 selector: 'my-video-upload', 15 selector: 'my-video-upload',
@@ -129,17 +130,17 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
129 cancelUpload () { 130 cancelUpload () {
130 if (this.videoUploadObservable !== null) { 131 if (this.videoUploadObservable !== null) {
131 this.videoUploadObservable.unsubscribe() 132 this.videoUploadObservable.unsubscribe()
133 }
132 134
133 this.isUploadingVideo = false 135 this.isUploadingVideo = false
134 this.videoUploadPercents = 0 136 this.videoUploadPercents = 0
135 this.videoUploadObservable = null 137 this.videoUploadObservable = null
136 138
137 this.firstStepError.emit() 139 this.firstStepError.emit()
138 this.enableRetryAfterError = false 140 this.enableRetryAfterError = false
139 this.error = '' 141 this.error = ''
140 142
141 this.notifier.info($localize`Upload cancelled`) 143 this.notifier.info($localize`Upload cancelled`)
142 }
143 } 144 }
144 145
145 uploadFirstStep (clickedOnButton = false) { 146 uploadFirstStep (clickedOnButton = false) {
@@ -229,6 +230,11 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
229 notifier: this.notifier, 230 notifier: this.notifier,
230 sticky: false 231 sticky: false
231 }) 232 })
233
234 if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413 ||
235 err.status === HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) {
236 this.cancelUpload()
237 }
232 } 238 }
233 ) 239 )
234 } 240 }
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts
index b15de2a79..33de901c0 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -39,6 +39,7 @@ import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils'
39import { environment } from '../../../environments/environment' 39import { environment } from '../../../environments/environment'
40import { VideoSupportComponent } from './modal/video-support.component' 40import { VideoSupportComponent } from './modal/video-support.component'
41import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' 41import { VideoWatchPlaylistComponent } from './video-watch-playlist.component'
42import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
42 43
43type URLOptions = CustomizationOptions & { playerMode: PlayerMode } 44type URLOptions = CustomizationOptions & { playerMode: PlayerMode }
44 45
@@ -412,13 +413,25 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
412 $localize`This video is not available on this instance. Do you want to be redirected on the origin instance: <a href="${originUrl}">${originUrl}</a>?`, 413 $localize`This video is not available on this instance. Do you want to be redirected on the origin instance: <a href="${originUrl}">${originUrl}</a>?`,
413 $localize`Redirection` 414 $localize`Redirection`
414 ).then(res => { 415 ).then(res => {
415 if (res === false) return this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ]) 416 if (res === false) {
417 return this.restExtractor.redirectTo404IfNotFound(err, [
418 HttpStatusCode.BAD_REQUEST_400,
419 HttpStatusCode.UNAUTHORIZED_401,
420 HttpStatusCode.FORBIDDEN_403,
421 HttpStatusCode.NOT_FOUND_404
422 ])
423 }
416 424
417 return window.location.href = originUrl 425 return window.location.href = originUrl
418 }) 426 })
419 } 427 }
420 428
421 return this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ]) 429 return this.restExtractor.redirectTo404IfNotFound(err, [
430 HttpStatusCode.BAD_REQUEST_400,
431 HttpStatusCode.UNAUTHORIZED_401,
432 HttpStatusCode.FORBIDDEN_403,
433 HttpStatusCode.NOT_FOUND_404
434 ])
422 }) 435 })
423 ) 436 )
424 .subscribe(([ video, captionsResult ]) => { 437 .subscribe(([ video, captionsResult ]) => {
@@ -450,7 +463,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
450 this.playlistService.getVideoPlaylist(playlistId) 463 this.playlistService.getVideoPlaylist(playlistId)
451 .pipe( 464 .pipe(
452 // If 401, the video is private or blocked so redirect to 404 465 // If 401, the video is private or blocked so redirect to 404
453 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])) 466 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [
467 HttpStatusCode.BAD_REQUEST_400,
468 HttpStatusCode.UNAUTHORIZED_401,
469 HttpStatusCode.FORBIDDEN_403,
470 HttpStatusCode.NOT_FOUND_404
471 ]))
454 ) 472 )
455 .subscribe(playlist => { 473 .subscribe(playlist => {
456 this.playlist = playlist 474 this.playlist = playlist
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index fd6062d3f..cdf13186b 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -11,6 +11,7 @@ import { environment } from '../../../environments/environment'
11import { RestExtractor } from '../rest/rest-extractor.service' 11import { RestExtractor } from '../rest/rest-extractor.service'
12import { AuthStatus } from './auth-status.model' 12import { AuthStatus } from './auth-status.model'
13import { AuthUser } from './auth-user.model' 13import { AuthUser } from './auth-user.model'
14import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
14 15
15interface UserLoginWithUsername extends UserLogin { 16interface UserLoginWithUsername extends UserLogin {
16 access_token: string 17 access_token: string
@@ -94,7 +95,7 @@ export class AuthService {
94 error => { 95 error => {
95 let errorMessage = error.message 96 let errorMessage = error.message
96 97
97 if (error.status === 403) { 98 if (error.status === HttpStatusCode.FORBIDDEN_403) {
98 errorMessage = $localize`Cannot retrieve OAuth Client credentials: ${error.text}. 99 errorMessage = $localize`Cannot retrieve OAuth Client credentials: ${error.text}.
99Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.` 100Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.`
100 } 101 }
diff --git a/client/src/app/core/rest/rest-extractor.service.ts b/client/src/app/core/rest/rest-extractor.service.ts
index 4b8c1e155..84d9ed074 100644
--- a/client/src/app/core/rest/rest-extractor.service.ts
+++ b/client/src/app/core/rest/rest-extractor.service.ts
@@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'
3import { Router } from '@angular/router' 3import { Router } from '@angular/router'
4import { dateToHuman } from '@app/helpers' 4import { dateToHuman } from '@app/helpers'
5import { ResultList } from '@shared/models' 5import { ResultList } from '@shared/models'
6import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
6 7
7@Injectable() 8@Injectable()
8export class RestExtractor { 9export class RestExtractor {
@@ -57,9 +58,9 @@ export class RestExtractor {
57 errorMessage = errorsArray.join('. ') 58 errorMessage = errorsArray.join('. ')
58 } else if (err.error && err.error.error) { 59 } else if (err.error && err.error.error) {
59 errorMessage = err.error.error 60 errorMessage = err.error.error
60 } else if (err.status === 413) { 61 } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) {
61 errorMessage = $localize`Media is too large for the server. Please contact you administrator if you want to increase the limit size.` 62 errorMessage = $localize`Media is too large for the server. Please contact you administrator if you want to increase the limit size.`
62 } else if (err.status === 429) { 63 } else if (err.status === HttpStatusCode.TOO_MANY_REQUESTS_429) {
63 const secondsLeft = err.headers.get('retry-after') 64 const secondsLeft = err.headers.get('retry-after')
64 if (secondsLeft) { 65 if (secondsLeft) {
65 const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60) 66 const minutesLeft = Math.floor(parseInt(secondsLeft, 10) / 60)
@@ -67,7 +68,7 @@ export class RestExtractor {
67 } else { 68 } else {
68 errorMessage = $localize`Too many attempts, please try again later.` 69 errorMessage = $localize`Too many attempts, please try again later.`
69 } 70 }
70 } else if (err.status === 500) { 71 } else if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) {
71 errorMessage = $localize`Server error. Please retry later.` 72 errorMessage = $localize`Server error. Please retry later.`
72 } 73 }
73 74
@@ -92,7 +93,7 @@ export class RestExtractor {
92 return observableThrowError(errorObj) 93 return observableThrowError(errorObj)
93 } 94 }
94 95
95 redirectTo404IfNotFound (obj: { status: number }, status = [ 404 ]) { 96 redirectTo404IfNotFound (obj: { status: number }, status = [ HttpStatusCode.NOT_FOUND_404 ]) {
96 if (obj && obj.status && status.indexOf(obj.status) !== -1) { 97 if (obj && obj.status && status.indexOf(obj.status) !== -1) {
97 // Do not use redirectService to avoid circular dependencies 98 // Do not use redirectService to avoid circular dependencies
98 this.router.navigate([ '/404' ], { skipLocationChange: true }) 99 this.router.navigate([ '/404' ], { skipLocationChange: true })
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index 48f7e7749..1709d44e7 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -13,6 +13,7 @@ import {
13 PluginType, 13 PluginType,
14 ClientHookName 14 ClientHookName
15} from '../../../../shared/models' 15} from '../../../../shared/models'
16import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
16import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode } from '../../assets/player/peertube-player-manager' 17import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode } from '../../assets/player/peertube-player-manager'
17import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' 18import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
18import { TranslationsManager } from '../../assets/player/translations-manager' 19import { TranslationsManager } from '../../assets/player/translations-manager'
@@ -85,7 +86,7 @@ export class PeerTubeEmbed {
85 refreshFetch (url: string, options?: RequestInit) { 86 refreshFetch (url: string, options?: RequestInit) {
86 return fetch(url, options) 87 return fetch(url, options)
87 .then((res: Response) => { 88 .then((res: Response) => {
88 if (res.status !== 401) return res 89 if (res.status !== HttpStatusCode.UNAUTHORIZED_401) return res
89 90
90 const refreshingTokenPromise = new Promise((resolve, reject) => { 91 const refreshingTokenPromise = new Promise((resolve, reject) => {
91 const clientId: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID) 92 const clientId: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID)
@@ -107,7 +108,7 @@ export class PeerTubeEmbed {
107 method: 'POST', 108 method: 'POST',
108 body: objectToUrlEncoded(data) 109 body: objectToUrlEncoded(data)
109 }).then(res => { 110 }).then(res => {
110 if (res.status === 401) return undefined 111 if (res.status === HttpStatusCode.UNAUTHORIZED_401) return undefined
111 112
112 return res.json() 113 return res.json()
113 }).then((obj: UserRefreshToken & { code: 'invalid_grant'}) => { 114 }).then((obj: UserRefreshToken & { code: 'invalid_grant'}) => {
@@ -338,7 +339,7 @@ export class PeerTubeEmbed {
338 339
339 try { 340 try {
340 playlistResponse = await playlistPromise 341 playlistResponse = await playlistPromise
341 isResponseOk = playlistResponse.status === 200 342 isResponseOk = playlistResponse.status === HttpStatusCode.OK_200
342 } catch (err) { 343 } catch (err) {
343 console.error(err) 344 console.error(err)
344 isResponseOk = false 345 isResponseOk = false
@@ -347,7 +348,7 @@ export class PeerTubeEmbed {
347 if (!isResponseOk) { 348 if (!isResponseOk) {
348 const serverTranslations = await this.translationsPromise 349 const serverTranslations = await this.translationsPromise
349 350
350 if (playlistResponse?.status === 404) { 351 if (playlistResponse?.status === HttpStatusCode.NOT_FOUND_404) {
351 this.playlistNotFound(serverTranslations) 352 this.playlistNotFound(serverTranslations)
352 return undefined 353 return undefined
353 } 354 }
@@ -367,7 +368,7 @@ export class PeerTubeEmbed {
367 368
368 try { 369 try {
369 videoResponse = await videoPromise 370 videoResponse = await videoPromise
370 isResponseOk = videoResponse.status === 200 371 isResponseOk = videoResponse.status === HttpStatusCode.OK_200
371 } catch (err) { 372 } catch (err) {
372 console.error(err) 373 console.error(err)
373 374
@@ -377,7 +378,7 @@ export class PeerTubeEmbed {
377 if (!isResponseOk) { 378 if (!isResponseOk) {
378 const serverTranslations = await this.translationsPromise 379 const serverTranslations = await this.translationsPromise
379 380
380 if (videoResponse?.status === 404) { 381 if (videoResponse?.status === HttpStatusCode.NOT_FOUND_404) {
381 this.videoNotFound(serverTranslations) 382 this.videoNotFound(serverTranslations)
382 return undefined 383 return undefined
383 } 384 }