switchMap(accountId => this.accountService.getAccount(accountId)),
tap(account => this.onAccount(account)),
switchMap(account => this.videoChannelService.listAccountVideoChannels(account)),
- catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [
+ catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [
HttpStatusCode.BAD_REQUEST_400,
HttpStatusCode.NOT_FOUND_404
]))
<div class="root">
- <div *ngIf="status === 404" class="box">
+ <div *ngIf="status !== 403 && status !== 418" class="box">
<strong>{{ status }}.</strong>
<span class="ml-1 text-muted" i18n>That's an error.</span>
<div class="text mt-4" i18n>
- We couldn't find any ressource tied to the URL {{ pathname }} you were looking for.
+ We couldn't find any {{ getRessourceName() }} tied to the URL {{ pathname }} you were looking for.
</div>
<div class="text-muted mt-4">
<span i18n="Possible reasons preceding a list of reasons a `Not Found` error page may occur">Possible reasons:</span>
<ul>
- <li i18n>The page may have been moved or deleted</li>
<li i18n>You may have used an outdated or broken link</li>
+ <li i18n>The {{ getRessourceName() }} may have been moved or deleted</li>
<li i18n>You may have typed the address or URL incorrectly</li>
</ul>
</div>
</div>
+ <div *ngIf="status === 403" class="box">
+ <strong>{{ status }}.</strong>
+ <span class="ml-1 text-muted" i18n>You are not authorized here.</span>
+
+ <div class="text mt-4" i18n>
+ You might need to check your account is allowed by the {{ getRessourceName() }} or instance owner.
+ </div>
+ </div>
+
<div *ngIf="status === 418" class="box">
<strong>{{ status }}.</strong>
<span class="ml-1 text-muted">I'm a teapot.</span>
import { Component, OnInit } from '@angular/core'
import { Title } from '@angular/platform-browser'
+import { Router } from '@angular/router'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
@Component({
})
export class PageNotFoundComponent implements OnInit {
status = HttpStatusCode.NOT_FOUND_404
+ type: string
public constructor (
- private titleService: Title
- ) {}
+ private titleService: Title,
+ private router: Router
+ ) {
+ const state = this.router.getCurrentNavigation()?.extras.state
+ this.type = state?.type || this.type
+ this.status = state?.obj.status || this.status
+ }
ngOnInit () {
if (this.pathname.includes('teapot')) {
return window.location.pathname
}
+ getRessourceName () {
+ switch (this.type) {
+ case 'video':
+ return $localize`video`
+ default:
+ return $localize`ressource`
+ }
+ }
+
getMascotName () {
switch (this.status) {
case HttpStatusCode.I_AM_A_TEAPOT_418:
return 'happy'
+ case HttpStatusCode.FORBIDDEN_403:
+ return 'arguing'
case HttpStatusCode.NOT_FOUND_404:
default:
return 'defeated'
map(params => params[ 'videoChannelName' ]),
distinctUntilChanged(),
switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)),
- catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [
+ catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [
HttpStatusCode.BAD_REQUEST_400,
HttpStatusCode.NOT_FOUND_404
]))
this.videoCaptionService.listCaptions(videoId)
])
.pipe(
- // If 401, the video is private or blocked so redirect to 404
+ // If 400, 403 or 404, the video is private or blocked so redirect to 404
catchError(err => {
if (err.body.errorCode === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && err.body.originUrl) {
const search = window.location.search
$localize`Redirection`
).then(res => {
if (res === false) {
- return this.restExtractor.redirectTo404IfNotFound(err, [
+ return this.restExtractor.redirectTo404IfNotFound(err, 'video', [
HttpStatusCode.BAD_REQUEST_400,
- HttpStatusCode.UNAUTHORIZED_401,
HttpStatusCode.FORBIDDEN_403,
HttpStatusCode.NOT_FOUND_404
])
})
}
- return this.restExtractor.redirectTo404IfNotFound(err, [
+ return this.restExtractor.redirectTo404IfNotFound(err, 'video', [
HttpStatusCode.BAD_REQUEST_400,
- HttpStatusCode.UNAUTHORIZED_401,
HttpStatusCode.FORBIDDEN_403,
HttpStatusCode.NOT_FOUND_404
])
this.playlistService.getVideoPlaylist(playlistId)
.pipe(
- // If 401, the video is private or blocked so redirect to 404
- catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [
+ // If 400 or 403, the video is private or blocked so redirect to 404
+ catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'video', [
HttpStatusCode.BAD_REQUEST_400,
- HttpStatusCode.UNAUTHORIZED_401,
HttpStatusCode.FORBIDDEN_403,
HttpStatusCode.NOT_FOUND_404
]))
return observableThrowError(errorObj)
}
- redirectTo404IfNotFound (obj: { status: number }, status = [ HttpStatusCode.NOT_FOUND_404 ]) {
+ redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) {
if (obj && obj.status && status.indexOf(obj.status) !== -1) {
// Do not use redirectService to avoid circular dependencies
- this.router.navigate([ '/404' ], { skipLocationChange: true })
+ this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true })
}
return observableThrowError(obj)
-import { Observable, throwError as observableThrowError } from 'rxjs'
+import { Observable, of, throwError as observableThrowError } from 'rxjs'
import { catchError, switchMap } from 'rxjs/operators'
-import { HTTP_INTERCEPTORS, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'
+import { HTTP_INTERCEPTORS, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpErrorResponse } from '@angular/common/http'
import { Injectable, Injector } from '@angular/core'
import { AuthService } from '@app/core/auth/auth.service'
+import { Router } from '@angular/router'
+import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
private authService: AuthService
// https://github.com/angular/angular/issues/18224#issuecomment-316957213
- constructor (private injector: Injector) {}
+ constructor (private injector: Injector, private router: Router) {}
intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.authService === undefined) {
// Catch 401 errors (refresh token expired)
return next.handle(authReq)
.pipe(
- catchError(err => {
- if (err.status === 401 && err.error && err.error.code === 'invalid_token') {
+ catchError((err: HttpErrorResponse) => {
+ if (err.status === HttpStatusCode.UNAUTHORIZED_401 && err.error && err.error.code === 'invalid_token') {
return this.handleTokenExpired(req, next)
+ } else if (err.status === HttpStatusCode.UNAUTHORIZED_401) {
+ return this.handleNotAuthenticated(err)
}
return observableThrowError(err)
// Clone the request to add the new header
return req.clone({ headers: req.headers.set('Authorization', authHeaderValue) })
}
+
+ private handleNotAuthenticated (err: HttpErrorResponse, path = '/login'): Observable<any> {
+ this.router.navigateByUrl(path)
+ return of(err.message)
+ }
}
export const AUTH_INTERCEPTOR_PROVIDER = {