diff options
author | Chocobozzz <me@florianbigard.com> | 2018-05-31 11:35:01 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-05-31 14:24:13 +0200 |
commit | a51bad1accfade25916db0dadaeb879a182cf19b (patch) | |
tree | 128330863a1125be437cf8ba9bc0c6c529068520 | |
parent | 351d5225d6a4fe6863f760f02454eac88f730607 (diff) | |
download | PeerTube-a51bad1accfade25916db0dadaeb879a182cf19b.tar.gz PeerTube-a51bad1accfade25916db0dadaeb879a182cf19b.tar.zst PeerTube-a51bad1accfade25916db0dadaeb879a182cf19b.zip |
Add 404 page
13 files changed, 126 insertions, 41 deletions
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' | |||
2 | import { ActivatedRoute } from '@angular/router' | 2 | import { ActivatedRoute } from '@angular/router' |
3 | import { AccountService } from '@app/shared/account/account.service' | 3 | import { AccountService } from '@app/shared/account/account.service' |
4 | import { Account } from '@app/shared/account/account.model' | 4 | import { Account } from '@app/shared/account/account.model' |
5 | import { RestExtractor } from '@app/shared' | ||
6 | import { catchError } from 'rxjs/operators' | ||
5 | 7 | ||
6 | @Component({ | 8 | @Component({ |
7 | templateUrl: './accounts.component.html', | 9 | templateUrl: './accounts.component.html', |
@@ -12,13 +14,15 @@ export class AccountsComponent implements OnInit { | |||
12 | 14 | ||
13 | constructor ( | 15 | constructor ( |
14 | private route: ActivatedRoute, | 16 | private route: ActivatedRoute, |
15 | private accountService: AccountService | 17 | private accountService: AccountService, |
18 | private restExtractor: RestExtractor | ||
16 | ) {} | 19 | ) {} |
17 | 20 | ||
18 | ngOnInit () { | 21 | ngOnInit () { |
19 | const accountId = this.route.snapshot.params['accountId'] | 22 | const accountId = this.route.snapshot.params['accountId'] |
20 | 23 | ||
21 | this.accountService.getAccount(accountId) | 24 | this.accountService.getAccount(accountId) |
25 | .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ]))) | ||
22 | .subscribe(account => this.account = account) | 26 | .subscribe(account => this.account = account) |
23 | } | 27 | } |
24 | } | 28 | } |
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 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { RouterModule, Routes } from '@angular/router' | ||
3 | import { PageNotFoundComponent } from './page-not-found.component' | ||
4 | |||
5 | const pageNotFoundRoutes: Routes = [ | ||
6 | { | ||
7 | path: '', | ||
8 | component: PageNotFoundComponent, | ||
9 | } | ||
10 | ] | ||
11 | |||
12 | @NgModule({ | ||
13 | imports: [ RouterModule.forChild(pageNotFoundRoutes) ], | ||
14 | exports: [ RouterModule ] | ||
15 | }) | ||
16 | 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 @@ | |||
1 | <div> | ||
2 | Sorry, but we couldn't find the page you were looking for. | ||
3 | </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 index 000000000..05d45f97f --- /dev/null +++ b/client/src/app/+page-not-found/page-not-found.component.scss | |||
@@ -0,0 +1,8 @@ | |||
1 | div { | ||
2 | height: 100%; | ||
3 | width: 100%; | ||
4 | text-align: center; | ||
5 | margin-top: 50px; | ||
6 | |||
7 | font-size: 32px; | ||
8 | } \ 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 @@ | |||
1 | import { Component } from '@angular/core' | ||
2 | |||
3 | @Component({ | ||
4 | selector: 'my-page-not-found', | ||
5 | templateUrl: './page-not-found.component.html', | ||
6 | styleUrls: [ './page-not-found.component.scss' ] | ||
7 | }) | ||
8 | export class PageNotFoundComponent { | ||
9 | |||
10 | } | ||
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 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { SharedModule } from '../shared' | ||
3 | import { PageNotFoundComponent } from '@app/+page-not-found/page-not-found.component' | ||
4 | import { PageNotFoundRoutingModule } from '@app/+page-not-found/page-not-found-routing.module' | ||
5 | |||
6 | @NgModule({ | ||
7 | imports: [ | ||
8 | PageNotFoundRoutingModule, | ||
9 | SharedModule | ||
10 | ], | ||
11 | |||
12 | declarations: [ | ||
13 | PageNotFoundComponent, | ||
14 | ], | ||
15 | |||
16 | exports: [ | ||
17 | PageNotFoundComponent | ||
18 | ], | ||
19 | |||
20 | providers: [] | ||
21 | }) | ||
22 | 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' | |||
2 | import { ActivatedRoute } from '@angular/router' | 2 | import { ActivatedRoute } from '@angular/router' |
3 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | 3 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' |
4 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | 4 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' |
5 | import { RestExtractor } from '@app/shared' | ||
6 | import { catchError } from 'rxjs/operators' | ||
5 | 7 | ||
6 | @Component({ | 8 | @Component({ |
7 | templateUrl: './video-channels.component.html', | 9 | templateUrl: './video-channels.component.html', |
@@ -12,13 +14,15 @@ export class VideoChannelsComponent implements OnInit { | |||
12 | 14 | ||
13 | constructor ( | 15 | constructor ( |
14 | private route: ActivatedRoute, | 16 | private route: ActivatedRoute, |
15 | private videoChannelService: VideoChannelService | 17 | private videoChannelService: VideoChannelService, |
18 | private restExtractor: RestExtractor | ||
16 | ) {} | 19 | ) {} |
17 | 20 | ||
18 | ngOnInit () { | 21 | ngOnInit () { |
19 | const videoChannelId = this.route.snapshot.params['videoChannelId'] | 22 | const videoChannelId = this.route.snapshot.params['videoChannelId'] |
20 | 23 | ||
21 | this.videoChannelService.getVideoChannel(videoChannelId) | 24 | this.videoChannelService.getVideoChannel(videoChannelId) |
25 | .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ]))) | ||
22 | .subscribe(videoChannel => this.videoChannel = videoChannel) | 26 | .subscribe(videoChannel => this.videoChannel = videoChannel) |
23 | } | 27 | } |
24 | } | 28 | } |
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 = [ | |||
19 | { | 19 | { |
20 | path: 'video-channels', | 20 | path: 'video-channels', |
21 | loadChildren: './+video-channels/video-channels.module#VideoChannelsModule' | 21 | loadChildren: './+video-channels/video-channels.module#VideoChannelsModule' |
22 | }, | ||
23 | { | ||
24 | path: '**', | ||
25 | loadChildren: './+page-not-found/page-not-found.module#PageNotFoundModule' | ||
22 | } | 26 | } |
23 | ] | 27 | ] |
24 | 28 | ||
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 { | |||
45 | CoreModule, | 45 | CoreModule, |
46 | SharedModule, | 46 | SharedModule, |
47 | 47 | ||
48 | AppRoutingModule, | ||
49 | |||
50 | CoreModule, | 48 | CoreModule, |
51 | LoginModule, | 49 | LoginModule, |
52 | ResetPasswordModule, | 50 | ResetPasswordModule, |
@@ -59,7 +57,9 @@ export function metaFactory (serverService: ServerService): MetaLoader { | |||
59 | provide: MetaLoader, | 57 | provide: MetaLoader, |
60 | useFactory: (metaFactory), | 58 | useFactory: (metaFactory), |
61 | deps: [ ServerService ] | 59 | deps: [ ServerService ] |
62 | }) | 60 | }), |
61 | |||
62 | AppRoutingModule, // Put it after all the module because it has the 404 route | ||
63 | ], | 63 | ], |
64 | providers: [ ] | 64 | providers: [ ] |
65 | }) | 65 | }) |
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 { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | this.serverService.configLoaded | 21 | this.serverService.configLoaded |
22 | .subscribe(() => { | 22 | .subscribe(() => { |
23 | const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute | 23 | const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute |
24 | 24 | ||
25 | if (defaultRouteConfig) { | 25 | if (defaultRouteConfig) { |
26 | RedirectService.DEFAULT_ROUTE = defaultRouteConfig | 26 | RedirectService.DEFAULT_ROUTE = defaultRouteConfig |
27 | } | 27 | } |
28 | }) | 28 | }) |
29 | } | 29 | } |
30 | 30 | ||
31 | redirectToHomepage () { | 31 | redirectToHomepage () { |
32 | console.log('Redirecting to %s...', RedirectService.DEFAULT_ROUTE) | 32 | console.log('Redirecting to %s...', RedirectService.DEFAULT_ROUTE) |
33 | 33 | ||
34 | this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { replaceUrl: true }) | 34 | this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { replaceUrl: true }) |
35 | .catch(() => { | 35 | .catch(() => { |
36 | console.error( | 36 | console.error( |
37 | 'Cannot navigate to %s, resetting default route to %s.', | 37 | 'Cannot navigate to %s, resetting default route to %s.', |
38 | RedirectService.DEFAULT_ROUTE, | 38 | RedirectService.DEFAULT_ROUTE, |
39 | RedirectService.INIT_DEFAULT_ROUTE | 39 | RedirectService.INIT_DEFAULT_ROUTE |
40 | ) | 40 | ) |
41 | 41 | ||
42 | RedirectService.DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE | 42 | RedirectService.DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE |
43 | return this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { replaceUrl: true }) | 43 | return this.router.navigate([ RedirectService.DEFAULT_ROUTE ], { replaceUrl: true }) |
44 | }) | 44 | }) |
45 | 45 | ||
46 | } | 46 | } |
47 | |||
48 | } | 47 | } |
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 @@ | |||
1 | import { of, throwError as observableThrowError } from 'rxjs' | 1 | import { throwError as observableThrowError } from 'rxjs' |
2 | import { Injectable } from '@angular/core' | 2 | import { Injectable } from '@angular/core' |
3 | import { dateToHuman } from '@app/shared/misc/utils' | 3 | import { dateToHuman } from '@app/shared/misc/utils' |
4 | import { ResultList } from '../../../../../shared' | 4 | import { ResultList } from '../../../../../shared' |
5 | import { Router } from '@angular/router' | ||
5 | 6 | ||
6 | @Injectable() | 7 | @Injectable() |
7 | export class RestExtractor { | 8 | export class RestExtractor { |
8 | 9 | ||
10 | constructor (private router: Router) { | ||
11 | // empty | ||
12 | } | ||
13 | |||
9 | extractDataBool () { | 14 | extractDataBool () { |
10 | return true | 15 | return true |
11 | } | 16 | } |
@@ -87,4 +92,13 @@ export class RestExtractor { | |||
87 | 92 | ||
88 | return observableThrowError(errorObj) | 93 | return observableThrowError(errorObj) |
89 | } | 94 | } |
95 | |||
96 | redirectTo404IfNotFound (obj: { status: number }, status = [ 404 ]) { | ||
97 | if (obj && obj.status && status.indexOf(obj.status) !== -1) { | ||
98 | // Do not use redirectService to avoid circular dependencies | ||
99 | this.router.navigate([ '/404' ], { skipLocationChange: true }) | ||
100 | } | ||
101 | |||
102 | return observableThrowError(obj) | ||
103 | } | ||
90 | } | 104 | } |
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 @@ | |||
1 | import { catchError } from 'rxjs/operators' | ||
1 | import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' | 2 | import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { RedirectService } from '@app/core/routing/redirect.service' | 4 | import { RedirectService } from '@app/core/routing/redirect.service' |
@@ -12,7 +13,7 @@ import * as WebTorrent from 'webtorrent' | |||
12 | import { UserVideoRateType, VideoRateType } from '../../../../../shared' | 13 | import { UserVideoRateType, VideoRateType } from '../../../../../shared' |
13 | import '../../../assets/player/peertube-videojs-plugin' | 14 | import '../../../assets/player/peertube-videojs-plugin' |
14 | import { AuthService, ConfirmService } from '../../core' | 15 | import { AuthService, ConfirmService } from '../../core' |
15 | import { VideoBlacklistService } from '../../shared' | 16 | import { RestExtractor, VideoBlacklistService } from '../../shared' |
16 | import { VideoDetails } from '../../shared/video/video-details.model' | 17 | import { VideoDetails } from '../../shared/video/video-details.model' |
17 | import { Video } from '../../shared/video/video.model' | 18 | import { Video } from '../../shared/video/video.model' |
18 | import { VideoService } from '../../shared/video/video.service' | 19 | import { VideoService } from '../../shared/video/video.service' |
@@ -65,6 +66,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
65 | private metaService: MetaService, | 66 | private metaService: MetaService, |
66 | private authService: AuthService, | 67 | private authService: AuthService, |
67 | private serverService: ServerService, | 68 | private serverService: ServerService, |
69 | private restExtractor: RestExtractor, | ||
68 | private notificationsService: NotificationsService, | 70 | private notificationsService: NotificationsService, |
69 | private markdownService: MarkdownService, | 71 | private markdownService: MarkdownService, |
70 | private zone: NgZone, | 72 | private zone: NgZone, |
@@ -99,21 +101,25 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
99 | } | 101 | } |
100 | 102 | ||
101 | const uuid = routeParams['uuid'] | 103 | const uuid = routeParams['uuid'] |
104 | |||
102 | // Video did not change | 105 | // Video did not change |
103 | if (this.video && this.video.uuid === uuid) return | 106 | if (this.video && this.video.uuid === uuid) return |
104 | // Video did change | 107 | // Video did change |
105 | this.videoService.getVideo(uuid).subscribe( | 108 | this.videoService |
106 | video => { | 109 | .getVideo(uuid) |
107 | const startTime = this.route.snapshot.queryParams.start | 110 | .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ]))) |
108 | this.onVideoFetched(video, startTime) | 111 | .subscribe( |
109 | .catch(err => this.handleError(err)) | 112 | video => { |
110 | }, | 113 | const startTime = this.route.snapshot.queryParams.start |
111 | 114 | this.onVideoFetched(video, startTime) | |
112 | error => { | 115 | .catch(err => this.handleError(err)) |
113 | this.videoNotFound = true | 116 | }, |
114 | console.error(error) | 117 | |
115 | } | 118 | error => { |
116 | ) | 119 | this.videoNotFound = true |
120 | console.error(error) | ||
121 | } | ||
122 | ) | ||
117 | }) | 123 | }) |
118 | } | 124 | } |
119 | 125 | ||
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 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes, UrlSegment } from '@angular/router' |
3 | import { VideoLocalComponent } from '@app/videos/video-list/video-local.component' | 3 | import { VideoLocalComponent } from '@app/videos/video-list/video-local.component' |
4 | import { MetaGuard } from '@ngx-meta/core' | 4 | import { MetaGuard } from '@ngx-meta/core' |
5 | import { VideoSearchComponent } from './video-list' | 5 | import { VideoSearchComponent } from './video-list' |
@@ -73,11 +73,6 @@ const videosRoutes: Routes = [ | |||
73 | } | 73 | } |
74 | }, | 74 | }, |
75 | { | 75 | { |
76 | path: ':uuid', | ||
77 | pathMatch: 'full', | ||
78 | redirectTo: 'watch/:uuid' | ||
79 | }, | ||
80 | { | ||
81 | path: 'watch/:uuid', | 76 | path: 'watch/:uuid', |
82 | loadChildren: 'app/videos/+video-watch/video-watch.module#VideoWatchModule', | 77 | loadChildren: 'app/videos/+video-watch/video-watch.module#VideoWatchModule', |
83 | data: { | 78 | data: { |