diff --git a/client/src/app/+accounts/accounts.component.ts b/client/src/app/+accounts/accounts.component.ts
index 0a52985da..24bde61ce 100644
--- a/client/src/app/+accounts/accounts.component.ts
+++ b/client/src/app/+accounts/accounts.component.ts
@@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { AccountService } from '@app/shared/account/account.service'
import { Account } from '@app/shared/account/account.model'
+import { RestExtractor } from '@app/shared'
+import { catchError } from 'rxjs/operators'
@Component({
templateUrl: './accounts.component.html',
@@ -12,13 +14,15 @@ export class AccountsComponent implements OnInit {
constructor (
private route: ActivatedRoute,
- private accountService: AccountService
+ private accountService: AccountService,
+ private restExtractor: RestExtractor
) {}
ngOnInit () {
const accountId = this.route.snapshot.params['accountId']
this.accountService.getAccount(accountId)
+ .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])))
.subscribe(account => this.account = account)
}
}
diff --git a/client/src/app/+page-not-found/page-not-found-routing.module.ts b/client/src/app/+page-not-found/page-not-found-routing.module.ts
new file mode 100644
index 000000000..43f7d7337
--- /dev/null
+++ b/client/src/app/+page-not-found/page-not-found-routing.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core'
+import { RouterModule, Routes } from '@angular/router'
+import { PageNotFoundComponent } from './page-not-found.component'
+
+const pageNotFoundRoutes: Routes = [
+ {
+ path: '',
+ component: PageNotFoundComponent,
+ }
+]
+
+@NgModule({
+ imports: [ RouterModule.forChild(pageNotFoundRoutes) ],
+ exports: [ RouterModule ]
+})
+export class PageNotFoundRoutingModule {}
diff --git a/client/src/app/+page-not-found/page-not-found.component.html b/client/src/app/+page-not-found/page-not-found.component.html
new file mode 100644
index 000000000..66aa2aec7
--- /dev/null
+++ b/client/src/app/+page-not-found/page-not-found.component.html
@@ -0,0 +1,3 @@
+
+ Sorry, but we couldn't find the page you were looking for.
+
\ No newline at end of file
diff --git a/client/src/app/+page-not-found/page-not-found.component.scss b/client/src/app/+page-not-found/page-not-found.component.scss
new file mode 100644
index 000000000..05d45f97f
--- /dev/null
+++ b/client/src/app/+page-not-found/page-not-found.component.scss
@@ -0,0 +1,8 @@
+div {
+ height: 100%;
+ width: 100%;
+ text-align: center;
+ margin-top: 50px;
+
+ font-size: 32px;
+}
\ No newline at end of file
diff --git a/client/src/app/+page-not-found/page-not-found.component.ts b/client/src/app/+page-not-found/page-not-found.component.ts
new file mode 100644
index 000000000..c91bb8649
--- /dev/null
+++ b/client/src/app/+page-not-found/page-not-found.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core'
+
+@Component({
+ selector: 'my-page-not-found',
+ templateUrl: './page-not-found.component.html',
+ styleUrls: [ './page-not-found.component.scss' ]
+})
+export class PageNotFoundComponent {
+
+}
diff --git a/client/src/app/+page-not-found/page-not-found.module.ts b/client/src/app/+page-not-found/page-not-found.module.ts
new file mode 100644
index 000000000..bc29d17c4
--- /dev/null
+++ b/client/src/app/+page-not-found/page-not-found.module.ts
@@ -0,0 +1,22 @@
+import { NgModule } from '@angular/core'
+import { SharedModule } from '../shared'
+import { PageNotFoundComponent } from '@app/+page-not-found/page-not-found.component'
+import { PageNotFoundRoutingModule } from '@app/+page-not-found/page-not-found-routing.module'
+
+@NgModule({
+ imports: [
+ PageNotFoundRoutingModule,
+ SharedModule
+ ],
+
+ declarations: [
+ PageNotFoundComponent,
+ ],
+
+ exports: [
+ PageNotFoundComponent
+ ],
+
+ providers: []
+})
+export class PageNotFoundModule { }
diff --git a/client/src/app/+video-channels/video-channels.component.ts b/client/src/app/+video-channels/video-channels.component.ts
index 5eca64fb5..09541b370 100644
--- a/client/src/app/+video-channels/video-channels.component.ts
+++ b/client/src/app/+video-channels/video-channels.component.ts
@@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
+import { RestExtractor } from '@app/shared'
+import { catchError } from 'rxjs/operators'
@Component({
templateUrl: './video-channels.component.html',
@@ -12,13 +14,15 @@ export class VideoChannelsComponent implements OnInit {
constructor (
private route: ActivatedRoute,
- private videoChannelService: VideoChannelService
+ private videoChannelService: VideoChannelService,
+ private restExtractor: RestExtractor
) {}
ngOnInit () {
const videoChannelId = this.route.snapshot.params['videoChannelId']
this.videoChannelService.getVideoChannel(videoChannelId)
+ .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])))
.subscribe(videoChannel => this.videoChannel = videoChannel)
}
}
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts
index 936912d28..04c53548e 100644
--- a/client/src/app/app-routing.module.ts
+++ b/client/src/app/app-routing.module.ts
@@ -19,6 +19,10 @@ const routes: Routes = [
{
path: 'video-channels',
loadChildren: './+video-channels/video-channels.module#VideoChannelsModule'
+ },
+ {
+ path: '**',
+ loadChildren: './+page-not-found/page-not-found.module#PageNotFoundModule'
}
]
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts
index 874fc43aa..0b4144e39 100644
--- a/client/src/app/app.module.ts
+++ b/client/src/app/app.module.ts
@@ -45,8 +45,6 @@ export function metaFactory (serverService: ServerService): MetaLoader {
CoreModule,
SharedModule,
- AppRoutingModule,
-
CoreModule,
LoginModule,
ResetPasswordModule,
@@ -59,7 +57,9 @@ export function metaFactory (serverService: ServerService): MetaLoader {
provide: MetaLoader,
useFactory: (metaFactory),
deps: [ ServerService ]
- })
+ }),
+
+ AppRoutingModule, // Put it after all the module because it has the 404 route
],
providers: [ ]
})
diff --git a/client/src/app/core/routing/redirect.service.ts b/client/src/app/core/routing/redirect.service.ts
index abe044d73..844f184b4 100644
--- a/client/src/app/core/routing/redirect.service.ts
+++ b/client/src/app/core/routing/redirect.service.ts
@@ -19,30 +19,29 @@ export class RedirectService {
}
this.serverService.configLoaded
- .subscribe(() => {
- const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute
+ .subscribe(() => {
+ const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute
- if (defaultRouteConfig) {
- RedirectService.DEFAULT_ROUTE = defaultRouteConfig
- }
- })
+ if (defaultRouteConfig) {
+ RedirectService.DEFAULT_ROUTE = defaultRouteConfig
+ }
+ })
}
redirectToHomepage () {
console.log('Redirecting to %s...', RedirectService.DEFAULT_ROUTE)
this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { replaceUrl: true })
- .catch(() => {
- console.error(
- 'Cannot navigate to %s, resetting default route to %s.',
- RedirectService.DEFAULT_ROUTE,
- RedirectService.INIT_DEFAULT_ROUTE
- )
+ .catch(() => {
+ console.error(
+ 'Cannot navigate to %s, resetting default route to %s.',
+ RedirectService.DEFAULT_ROUTE,
+ RedirectService.INIT_DEFAULT_ROUTE
+ )
- RedirectService.DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE
- return this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { replaceUrl: true })
- })
+ RedirectService.DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE
+ return this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { replaceUrl: true })
+ })
}
-
}
diff --git a/client/src/app/shared/rest/rest-extractor.service.ts b/client/src/app/shared/rest/rest-extractor.service.ts
index db087d407..39e601e20 100644
--- a/client/src/app/shared/rest/rest-extractor.service.ts
+++ b/client/src/app/shared/rest/rest-extractor.service.ts
@@ -1,11 +1,16 @@
-import { of, throwError as observableThrowError } from 'rxjs'
+import { throwError as observableThrowError } from 'rxjs'
import { Injectable } from '@angular/core'
import { dateToHuman } from '@app/shared/misc/utils'
import { ResultList } from '../../../../../shared'
+import { Router } from '@angular/router'
@Injectable()
export class RestExtractor {
+ constructor (private router: Router) {
+ // empty
+ }
+
extractDataBool () {
return true
}
@@ -87,4 +92,13 @@ export class RestExtractor {
return observableThrowError(errorObj)
}
+
+ redirectTo404IfNotFound (obj: { status: number }, status = [ 404 ]) {
+ if (obj && obj.status && status.indexOf(obj.status) !== -1) {
+ // Do not use redirectService to avoid circular dependencies
+ this.router.navigate([ '/404' ], { skipLocationChange: true })
+ }
+
+ return observableThrowError(obj)
+ }
}
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 c71051649..ad572ef58 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -1,3 +1,4 @@
+import { catchError } from 'rxjs/operators'
import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { RedirectService } from '@app/core/routing/redirect.service'
@@ -12,7 +13,7 @@ import * as WebTorrent from 'webtorrent'
import { UserVideoRateType, VideoRateType } from '../../../../../shared'
import '../../../assets/player/peertube-videojs-plugin'
import { AuthService, ConfirmService } from '../../core'
-import { VideoBlacklistService } from '../../shared'
+import { RestExtractor, VideoBlacklistService } from '../../shared'
import { VideoDetails } from '../../shared/video/video-details.model'
import { Video } from '../../shared/video/video.model'
import { VideoService } from '../../shared/video/video.service'
@@ -65,6 +66,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private metaService: MetaService,
private authService: AuthService,
private serverService: ServerService,
+ private restExtractor: RestExtractor,
private notificationsService: NotificationsService,
private markdownService: MarkdownService,
private zone: NgZone,
@@ -99,21 +101,25 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
}
const uuid = routeParams['uuid']
+
// Video did not change
if (this.video && this.video.uuid === uuid) return
// Video did change
- this.videoService.getVideo(uuid).subscribe(
- video => {
- const startTime = this.route.snapshot.queryParams.start
- this.onVideoFetched(video, startTime)
- .catch(err => this.handleError(err))
- },
+ this.videoService
+ .getVideo(uuid)
+ .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])))
+ .subscribe(
+ video => {
+ const startTime = this.route.snapshot.queryParams.start
+ this.onVideoFetched(video, startTime)
+ .catch(err => this.handleError(err))
+ },
- error => {
- this.videoNotFound = true
- console.error(error)
- }
- )
+ error => {
+ this.videoNotFound = true
+ console.error(error)
+ }
+ )
})
}
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts
index 572f33d5e..66153e033 100644
--- a/client/src/app/videos/videos-routing.module.ts
+++ b/client/src/app/videos/videos-routing.module.ts
@@ -1,5 +1,5 @@
import { NgModule } from '@angular/core'
-import { RouterModule, Routes } from '@angular/router'
+import { RouterModule, Routes, UrlSegment } from '@angular/router'
import { VideoLocalComponent } from '@app/videos/video-list/video-local.component'
import { MetaGuard } from '@ngx-meta/core'
import { VideoSearchComponent } from './video-list'
@@ -72,11 +72,6 @@ const videosRoutes: Routes = [
}
}
},
- {
- path: ':uuid',
- pathMatch: 'full',
- redirectTo: 'watch/:uuid'
- },
{
path: 'watch/:uuid',
loadChildren: 'app/videos/+video-watch/video-watch.module#VideoWatchModule',