Add 404 page
authorChocobozzz <me@florianbigard.com>
Thu, 31 May 2018 09:35:01 +0000 (11:35 +0200)
committerChocobozzz <me@florianbigard.com>
Thu, 31 May 2018 12:24:13 +0000 (14:24 +0200)
13 files changed:
client/src/app/+accounts/accounts.component.ts
client/src/app/+page-not-found/page-not-found-routing.module.ts [new file with mode: 0644]
client/src/app/+page-not-found/page-not-found.component.html [new file with mode: 0644]
client/src/app/+page-not-found/page-not-found.component.scss [new file with mode: 0644]
client/src/app/+page-not-found/page-not-found.component.ts [new file with mode: 0644]
client/src/app/+page-not-found/page-not-found.module.ts [new file with mode: 0644]
client/src/app/+video-channels/video-channels.component.ts
client/src/app/app-routing.module.ts
client/src/app/app.module.ts
client/src/app/core/routing/redirect.service.ts
client/src/app/shared/rest/rest-extractor.service.ts
client/src/app/videos/+video-watch/video-watch.component.ts
client/src/app/videos/videos-routing.module.ts

index 0a52985dad7af4cefccf0074f5490cdf392333da..24bde61ce1ef53701c67e460db0bf5d590ce035f 100644 (file)
@@ -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 (file)
index 0000000..43f7d73
--- /dev/null
@@ -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 (file)
index 0000000..66aa2ae
--- /dev/null
@@ -0,0 +1,3 @@
+<div>
+  Sorry, but we couldn't find the page you were looking for.
+</div>
\ 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 (file)
index 0000000..05d45f9
--- /dev/null
@@ -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 (file)
index 0000000..c91bb86
--- /dev/null
@@ -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 (file)
index 0000000..bc29d17
--- /dev/null
@@ -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 { }
index 5eca64fb55697e9c1c71c2250edbb807869d20d1..09541b370e52febb413ae2853058a40dbb6f22e0 100644 (file)
@@ -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)
   }
 }
index 936912d282fedddb07d171c6ccf593804da68729..04c53548eb375999361ab90a478ed9964450bcaf 100644 (file)
@@ -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'
   }
 ]
 
index 874fc43aa28cafdc1a2b177f7a00b323b6531693..0b4144e39080d883d7639c5674303fcb25ceb6b6 100644 (file)
@@ -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: [ ]
 })
index abe044d7306e007dbab9ef61084b345fdff0a53e..844f184b414ac6cb3baad62fcfa13c2b20d7450a 100644 (file)
@@ -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 })
+        })
 
   }
-
 }
index db087d407c1385451a0e30e05a2b596f3b672411..39e601e201f2900d8ea1e39cda817867b1a872b9 100644 (file)
@@ -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)
+  }
 }
index c710516490d377b7cac6ab48fff67102611c8e26..ad572ef58263c7cfa9b5e4cc3474a55933479cf3 100644 (file)
@@ -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))
-        },
-
-        error => {
-          this.videoNotFound = true
-          console.error(error)
-        }
-      )
+      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)
+            }
+          )
     })
   }
 
index 572f33d5e04577817bb01b15ec5d215836811d66..66153e0337a354a2c4db7f1a3fa7d52c3066975b 100644 (file)
@@ -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',