diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-01-23 22:16:48 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-01-23 22:18:53 +0100 |
commit | 11ac88de40215783835cf6e6259ff0f6cee258dd (patch) | |
tree | 9bdb69c0a4e3621b9b185d30a8a63f1ac6e8fbfa | |
parent | 4f8c0eb0e9356ee2782ea6eb12a92e4dc5f66127 (diff) | |
download | PeerTube-11ac88de40215783835cf6e6259ff0f6cee258dd.tar.gz PeerTube-11ac88de40215783835cf6e6259ff0f6cee258dd.tar.zst PeerTube-11ac88de40215783835cf6e6259ff0f6cee258dd.zip |
Client: add basic support to report video abuses
21 files changed, 185 insertions, 15 deletions
@@ -37,10 +37,6 @@ Prototype of a decentralized video streaming platform using P2P (BitTorrent) dir | |||
37 | <img src="https://david-dm.org/Chocobozzz/PeerTube/dev-status.svg" alt="devDependency Status" /> | 37 | <img src="https://david-dm.org/Chocobozzz/PeerTube/dev-status.svg" alt="devDependency Status" /> |
38 | </a> | 38 | </a> |
39 | 39 | ||
40 | <a href="https://codeclimate.com/github/Chocobozzz/PeerTube"> | ||
41 | <img src="https://codeclimate.com/github/Chocobozzz/PeerTube/badges/gpa.svg" alt="Code climate" /> | ||
42 | </a> | ||
43 | |||
44 | <a href="http://standardjs.com/"> | 40 | <a href="http://standardjs.com/"> |
45 | <img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg" alt="JavaScript Style Guide" /> | 41 | <img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg" alt="JavaScript Style Guide" /> |
46 | </a> | 42 | </a> |
diff --git a/client/src/app/admin/admin-routing.module.ts b/client/src/app/admin/admin-routing.module.ts index 6bff25033..cabc6df15 100644 --- a/client/src/app/admin/admin-routing.module.ts +++ b/client/src/app/admin/admin-routing.module.ts | |||
@@ -5,6 +5,7 @@ import { AdminComponent } from './admin.component'; | |||
5 | import { FriendsRoutes } from './friends'; | 5 | import { FriendsRoutes } from './friends'; |
6 | import { RequestsRoutes } from './requests'; | 6 | import { RequestsRoutes } from './requests'; |
7 | import { UsersRoutes } from './users'; | 7 | import { UsersRoutes } from './users'; |
8 | import { VideoAbusesRoutes } from './video-abuses'; | ||
8 | 9 | ||
9 | const adminRoutes: Routes = [ | 10 | const adminRoutes: Routes = [ |
10 | { | 11 | { |
@@ -18,7 +19,8 @@ const adminRoutes: Routes = [ | |||
18 | }, | 19 | }, |
19 | ...FriendsRoutes, | 20 | ...FriendsRoutes, |
20 | ...RequestsRoutes, | 21 | ...RequestsRoutes, |
21 | ...UsersRoutes | 22 | ...UsersRoutes, |
23 | ...VideoAbusesRoutes | ||
22 | ] | 24 | ] |
23 | } | 25 | } |
24 | ]; | 26 | ]; |
diff --git a/client/src/app/admin/admin.module.ts b/client/src/app/admin/admin.module.ts index 63d99a3db..d3ada8ce8 100644 --- a/client/src/app/admin/admin.module.ts +++ b/client/src/app/admin/admin.module.ts | |||
@@ -5,6 +5,7 @@ import { AdminRoutingModule } from './admin-routing.module'; | |||
5 | import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends'; | 5 | import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends'; |
6 | import { RequestsComponent, RequestStatsComponent, RequestService } from './requests'; | 6 | import { RequestsComponent, RequestStatsComponent, RequestService } from './requests'; |
7 | import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users'; | 7 | import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users'; |
8 | import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses'; | ||
8 | import { MenuAdminComponent } from './menu-admin.component'; | 9 | import { MenuAdminComponent } from './menu-admin.component'; |
9 | import { SharedModule } from '../shared'; | 10 | import { SharedModule } from '../shared'; |
10 | 11 | ||
@@ -28,6 +29,9 @@ import { SharedModule } from '../shared'; | |||
28 | UserAddComponent, | 29 | UserAddComponent, |
29 | UserListComponent, | 30 | UserListComponent, |
30 | 31 | ||
32 | VideoAbusesComponent, | ||
33 | VideoAbuseListComponent, | ||
34 | |||
31 | MenuAdminComponent | 35 | MenuAdminComponent |
32 | ], | 36 | ], |
33 | 37 | ||
diff --git a/client/src/app/admin/menu-admin.component.html b/client/src/app/admin/menu-admin.component.html index e250615aa..ad7a7a1b4 100644 --- a/client/src/app/admin/menu-admin.component.html +++ b/client/src/app/admin/menu-admin.component.html | |||
@@ -15,6 +15,11 @@ | |||
15 | <span class="hidden-xs glyphicon glyphicon-stats"></span> | 15 | <span class="hidden-xs glyphicon glyphicon-stats"></span> |
16 | <a [routerLink]="['/admin/requests/stats']">Request stats</a> | 16 | <a [routerLink]="['/admin/requests/stats']">Request stats</a> |
17 | </div> | 17 | </div> |
18 | |||
19 | <div id="panel-video-abuses" class="panel-button"> | ||
20 | <span class="hidden-xs glyphicon glyphicon-alert"></span> | ||
21 | <a [routerLink]="['/admin/video-abuses/list']">Video abuses</a> | ||
22 | </div> | ||
18 | </div> | 23 | </div> |
19 | 24 | ||
20 | <div class="panel-block"> | 25 | <div class="panel-block"> |
diff --git a/client/src/app/admin/video-abuses/index.ts b/client/src/app/admin/video-abuses/index.ts new file mode 100644 index 000000000..7f5e65f91 --- /dev/null +++ b/client/src/app/admin/video-abuses/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './video-abuse-list'; | ||
2 | export * from './video-abuses.component'; | ||
3 | export * from './video-abuses.routes'; | ||
diff --git a/client/src/app/admin/video-abuses/video-abuse-list/index.ts b/client/src/app/admin/video-abuses/video-abuse-list/index.ts new file mode 100644 index 000000000..3f2ed1714 --- /dev/null +++ b/client/src/app/admin/video-abuses/video-abuse-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './video-abuse-list.component'; | |||
diff --git a/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.html b/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.html new file mode 100644 index 000000000..46043577c --- /dev/null +++ b/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.html | |||
@@ -0,0 +1,27 @@ | |||
1 | <h3>Video abuses list</h3> | ||
2 | |||
3 | <table class="table table-hover"> | ||
4 | <thead> | ||
5 | <tr> | ||
6 | <th class="cell-id">ID</th> | ||
7 | <th class="cell-reason">Reason</th> | ||
8 | <th>Reporter pod host</th> | ||
9 | <th>Reporter username</th> | ||
10 | <th>Video</th> | ||
11 | <th>Created at</th> | ||
12 | </tr> | ||
13 | </thead> | ||
14 | |||
15 | <tbody> | ||
16 | <tr *ngFor="let videoAbuse of videoAbuses"> | ||
17 | <td>{{ videoAbuse.id }}</td> | ||
18 | <td>{{ videoAbuse.reason }}</td> | ||
19 | <td>{{ videoAbuse.reporterPodHost }}</td> | ||
20 | <td>{{ videoAbuse.reporterUsername }}</td> | ||
21 | <td> | ||
22 | <a [routerLink]="buildVideoLink(videoAbuse)" title="Go to video">{{ videoAbuse.videoId }}</a> | ||
23 | </td> | ||
24 | <td>{{ videoAbuse.createdAt | date: 'medium' }}</td> | ||
25 | </tr> | ||
26 | </tbody> | ||
27 | </table> | ||
diff --git a/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.scss b/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.scss new file mode 100644 index 000000000..a094f74b8 --- /dev/null +++ b/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.scss | |||
@@ -0,0 +1,7 @@ | |||
1 | .cell-id { | ||
2 | width: 40px; | ||
3 | } | ||
4 | |||
5 | .cell-reason { | ||
6 | width: 200px; | ||
7 | } | ||
diff --git a/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.ts b/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.ts new file mode 100644 index 000000000..de58bba3d --- /dev/null +++ b/client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.ts | |||
@@ -0,0 +1,31 @@ | |||
1 | import { setInterval } from 'timers' | ||
2 | import { Component, OnInit } from '@angular/core'; | ||
3 | |||
4 | import { VideoAbuseService, VideoAbuse} from '../../../shared'; | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-video-abuse-list', | ||
8 | templateUrl: './video-abuse-list.component.html', | ||
9 | styleUrls: [ './video-abuse-list.component.scss' ] | ||
10 | }) | ||
11 | export class VideoAbuseListComponent implements OnInit { | ||
12 | videoAbuses: VideoAbuse[]; | ||
13 | |||
14 | constructor(private videoAbuseService: VideoAbuseService) { } | ||
15 | |||
16 | ngOnInit() { | ||
17 | this.getVideoAbuses(); | ||
18 | } | ||
19 | |||
20 | buildVideoLink(videoAbuse: VideoAbuse) { | ||
21 | return `/videos/${videoAbuse.videoId}`; | ||
22 | } | ||
23 | |||
24 | private getVideoAbuses() { | ||
25 | this.videoAbuseService.getVideoAbuses().subscribe( | ||
26 | res => this.videoAbuses = res.videoAbuses, | ||
27 | |||
28 | err => alert(err.text) | ||
29 | ); | ||
30 | } | ||
31 | } | ||
diff --git a/client/src/app/admin/video-abuses/video-abuses.component.ts b/client/src/app/admin/video-abuses/video-abuses.component.ts new file mode 100644 index 000000000..001f27e87 --- /dev/null +++ b/client/src/app/admin/video-abuses/video-abuses.component.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { Component } from '@angular/core'; | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | |||
7 | export class VideoAbusesComponent { | ||
8 | } | ||
diff --git a/client/src/app/admin/video-abuses/video-abuses.routes.ts b/client/src/app/admin/video-abuses/video-abuses.routes.ts new file mode 100644 index 000000000..26a761887 --- /dev/null +++ b/client/src/app/admin/video-abuses/video-abuses.routes.ts | |||
@@ -0,0 +1,28 @@ | |||
1 | import { Routes } from '@angular/router'; | ||
2 | |||
3 | import { VideoAbusesComponent } from './video-abuses.component'; | ||
4 | import { VideoAbuseListComponent } from './video-abuse-list'; | ||
5 | |||
6 | export const VideoAbusesRoutes: Routes = [ | ||
7 | { | ||
8 | path: 'video-abuses', | ||
9 | component: VideoAbusesComponent | ||
10 | , | ||
11 | children: [ | ||
12 | { | ||
13 | path: '', | ||
14 | redirectTo: 'list', | ||
15 | pathMatch: 'full' | ||
16 | }, | ||
17 | { | ||
18 | path: 'list', | ||
19 | component: VideoAbuseListComponent, | ||
20 | data: { | ||
21 | meta: { | ||
22 | titleSuffix: ' - Video abuses list' | ||
23 | } | ||
24 | } | ||
25 | } | ||
26 | ] | ||
27 | } | ||
28 | ]; | ||
diff --git a/client/src/app/shared/forms/form-validators/index.ts b/client/src/app/shared/forms/form-validators/index.ts index 119b5d9bf..ab7c2df31 100644 --- a/client/src/app/shared/forms/form-validators/index.ts +++ b/client/src/app/shared/forms/form-validators/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './host.validator'; | 1 | export * from './host.validator'; |
2 | export * from './user'; | 2 | export * from './user'; |
3 | export * from './video-report'; | 3 | export * from './video-abuse'; |
4 | export * from './video'; | 4 | export * from './video'; |
diff --git a/client/src/app/shared/forms/form-validators/video-report.ts b/client/src/app/shared/forms/form-validators/video-abuse.ts index 036ee1721..94a29a3b7 100644 --- a/client/src/app/shared/forms/form-validators/video-report.ts +++ b/client/src/app/shared/forms/form-validators/video-abuse.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Validators } from '@angular/forms'; | 1 | import { Validators } from '@angular/forms'; |
2 | 2 | ||
3 | export const VIDEO_REPORT_REASON = { | 3 | export const VIDEO_ABUSE_REASON = { |
4 | VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ], | 4 | VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ], |
5 | MESSAGES: { | 5 | MESSAGES: { |
6 | 'required': 'Report reason name is required.', | 6 | 'required': 'Report reason name is required.', |
diff --git a/client/src/app/shared/index.ts b/client/src/app/shared/index.ts index 52a647b83..7876e6f14 100644 --- a/client/src/app/shared/index.ts +++ b/client/src/app/shared/index.ts | |||
@@ -3,4 +3,5 @@ export * from './forms'; | |||
3 | export * from './rest'; | 3 | export * from './rest'; |
4 | export * from './search'; | 4 | export * from './search'; |
5 | export * from './users'; | 5 | export * from './users'; |
6 | export * from './video-abuse'; | ||
6 | export * from './shared.module'; | 7 | export * from './shared.module'; |
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 748c5d520..7b2386d6c 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -14,6 +14,7 @@ import { FileUploadModule } from 'ng2-file-upload/ng2-file-upload'; | |||
14 | import { AUTH_HTTP_PROVIDERS } from './auth'; | 14 | import { AUTH_HTTP_PROVIDERS } from './auth'; |
15 | import { RestExtractor, RestService } from './rest'; | 15 | import { RestExtractor, RestService } from './rest'; |
16 | import { SearchComponent, SearchService } from './search'; | 16 | import { SearchComponent, SearchService } from './search'; |
17 | import { VideoAbuseService } from './video-abuse'; | ||
17 | 18 | ||
18 | @NgModule({ | 19 | @NgModule({ |
19 | imports: [ | 20 | imports: [ |
@@ -57,7 +58,8 @@ import { SearchComponent, SearchService } from './search'; | |||
57 | AUTH_HTTP_PROVIDERS, | 58 | AUTH_HTTP_PROVIDERS, |
58 | RestExtractor, | 59 | RestExtractor, |
59 | RestService, | 60 | RestService, |
60 | SearchService | 61 | SearchService, |
62 | VideoAbuseService | ||
61 | ] | 63 | ] |
62 | }) | 64 | }) |
63 | export class SharedModule { } | 65 | export class SharedModule { } |
diff --git a/client/src/app/shared/video-abuse/index.ts b/client/src/app/shared/video-abuse/index.ts new file mode 100644 index 000000000..563533ba5 --- /dev/null +++ b/client/src/app/shared/video-abuse/index.ts | |||
@@ -0,0 +1,2 @@ | |||
1 | export * from './video-abuse.service'; | ||
2 | export * from './video-abuse.model'; | ||
diff --git a/client/src/app/shared/video-abuse/video-abuse.model.ts b/client/src/app/shared/video-abuse/video-abuse.model.ts new file mode 100644 index 000000000..bb0373027 --- /dev/null +++ b/client/src/app/shared/video-abuse/video-abuse.model.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | export interface VideoAbuse { | ||
2 | id: string; | ||
3 | reason: string; | ||
4 | reporterPodHost: string; | ||
5 | reporterUsername: string; | ||
6 | videoId: string; | ||
7 | createdAt: Date; | ||
8 | } | ||
diff --git a/client/src/app/shared/video-abuse/video-abuse.service.ts b/client/src/app/shared/video-abuse/video-abuse.service.ts new file mode 100644 index 000000000..2750a41c7 --- /dev/null +++ b/client/src/app/shared/video-abuse/video-abuse.service.ts | |||
@@ -0,0 +1,44 @@ | |||
1 | import { Injectable } from '@angular/core'; | ||
2 | import { Http } from '@angular/http'; | ||
3 | import { Observable } from 'rxjs/Observable'; | ||
4 | import 'rxjs/add/operator/catch'; | ||
5 | import 'rxjs/add/operator/map'; | ||
6 | |||
7 | import { AuthService } from '../core'; | ||
8 | import { AuthHttp } from '../auth'; | ||
9 | import { RestExtractor, ResultList } from '../rest'; | ||
10 | import { VideoAbuse } from './video-abuse.model'; | ||
11 | |||
12 | @Injectable() | ||
13 | export class VideoAbuseService { | ||
14 | private static BASE_VIDEO_ABUSE_URL = '/api/v1/videos/'; | ||
15 | |||
16 | constructor( | ||
17 | private authHttp: AuthHttp, | ||
18 | private restExtractor: RestExtractor | ||
19 | ) {} | ||
20 | |||
21 | getVideoAbuses() { | ||
22 | return this.authHttp.get(VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse') | ||
23 | .map(this.restExtractor.extractDataList) | ||
24 | .map(this.extractVideoAbuses) | ||
25 | } | ||
26 | |||
27 | reportVideo(id: string, reason: string) { | ||
28 | const body = { | ||
29 | reason | ||
30 | }; | ||
31 | const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse'; | ||
32 | |||
33 | return this.authHttp.post(url, body) | ||
34 | .map(this.restExtractor.extractDataBool) | ||
35 | .catch((res) => this.restExtractor.handleError(res)); | ||
36 | } | ||
37 | |||
38 | private extractVideoAbuses(result: ResultList) { | ||
39 | const videoAbuses: VideoAbuse[] = result.data; | ||
40 | const totalVideoAbuses = result.total; | ||
41 | |||
42 | return { videoAbuses, totalVideoAbuses }; | ||
43 | } | ||
44 | } | ||
diff --git a/client/src/app/videos/video-watch/video-report.component.ts b/client/src/app/videos/video-watch/video-report.component.ts index 7bc1677ab..7a125f53e 100644 --- a/client/src/app/videos/video-watch/video-report.component.ts +++ b/client/src/app/videos/video-watch/video-report.component.ts | |||
@@ -3,7 +3,7 @@ import { FormBuilder, FormGroup } from '@angular/forms'; | |||
3 | 3 | ||
4 | import { ModalDirective } from 'ng2-bootstrap/modal'; | 4 | import { ModalDirective } from 'ng2-bootstrap/modal'; |
5 | 5 | ||
6 | import { FormReactive, VIDEO_REPORT_REASON } from '../../shared'; | 6 | import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared'; |
7 | import { Video, VideoService } from '../shared'; | 7 | import { Video, VideoService } from '../shared'; |
8 | 8 | ||
9 | @Component({ | 9 | @Component({ |
@@ -21,12 +21,12 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
21 | reason: '' | 21 | reason: '' |
22 | }; | 22 | }; |
23 | validationMessages = { | 23 | validationMessages = { |
24 | reason: VIDEO_REPORT_REASON.MESSAGES | 24 | reason: VIDEO_ABUSE_REASON.MESSAGES |
25 | }; | 25 | }; |
26 | 26 | ||
27 | constructor( | 27 | constructor( |
28 | private formBuilder: FormBuilder, | 28 | private formBuilder: FormBuilder, |
29 | private videoService: VideoService | 29 | private videoAbuseService: VideoAbuseService |
30 | ) { | 30 | ) { |
31 | super(); | 31 | super(); |
32 | } | 32 | } |
@@ -37,7 +37,7 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
37 | 37 | ||
38 | buildForm() { | 38 | buildForm() { |
39 | this.form = this.formBuilder.group({ | 39 | this.form = this.formBuilder.group({ |
40 | reason: [ '', VIDEO_REPORT_REASON.VALIDATORS ] | 40 | reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ] |
41 | }); | 41 | }); |
42 | 42 | ||
43 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 43 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); |
@@ -54,7 +54,7 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
54 | report() { | 54 | report() { |
55 | const reason = this.form.value['reason'] | 55 | const reason = this.form.value['reason'] |
56 | 56 | ||
57 | this.videoService.reportVideo(this.video.id, reason) | 57 | this.videoAbuseService.reportVideo(this.video.id, reason) |
58 | .subscribe( | 58 | .subscribe( |
59 | // TODO: move alert to beautiful notifications | 59 | // TODO: move alert to beautiful notifications |
60 | ok => { | 60 | ok => { |
diff --git a/server/initializers/database.js b/server/initializers/database.js index f8f68adeb..043152a0e 100644 --- a/server/initializers/database.js +++ b/server/initializers/database.js | |||
@@ -70,7 +70,7 @@ function init (silent, callback) { | |||
70 | } | 70 | } |
71 | }) | 71 | }) |
72 | 72 | ||
73 | if (!silent) logger.info('Database is ready.') | 73 | if (!silent) logger.info('Database %s is ready.', dbname) |
74 | 74 | ||
75 | return callback(null) | 75 | return callback(null) |
76 | }) | 76 | }) |
diff --git a/server/models/video-abuse.js b/server/models/video-abuse.js index 766a7568d..67cead3af 100644 --- a/server/models/video-abuse.js +++ b/server/models/video-abuse.js | |||
@@ -106,7 +106,8 @@ function toFormatedJSON () { | |||
106 | reporterPodHost, | 106 | reporterPodHost, |
107 | reason: this.reason, | 107 | reason: this.reason, |
108 | reporterUsername: this.reporterUsername, | 108 | reporterUsername: this.reporterUsername, |
109 | videoId: this.videoId | 109 | videoId: this.videoId, |
110 | createdAt: this.createdAt | ||
110 | } | 111 | } |
111 | 112 | ||
112 | return json | 113 | return json |