Client: add basic support to report video abuses
authorChocobozzz <florian.bigard@gmail.com>
Mon, 23 Jan 2017 21:16:48 +0000 (22:16 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Mon, 23 Jan 2017 21:18:53 +0000 (22:18 +0100)
22 files changed:
README.md
client/src/app/admin/admin-routing.module.ts
client/src/app/admin/admin.module.ts
client/src/app/admin/menu-admin.component.html
client/src/app/admin/video-abuses/index.ts [new file with mode: 0644]
client/src/app/admin/video-abuses/video-abuse-list/index.ts [new file with mode: 0644]
client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.html [new file with mode: 0644]
client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.scss [new file with mode: 0644]
client/src/app/admin/video-abuses/video-abuse-list/video-abuse-list.component.ts [new file with mode: 0644]
client/src/app/admin/video-abuses/video-abuses.component.ts [new file with mode: 0644]
client/src/app/admin/video-abuses/video-abuses.routes.ts [new file with mode: 0644]
client/src/app/shared/forms/form-validators/index.ts
client/src/app/shared/forms/form-validators/video-abuse.ts [new file with mode: 0644]
client/src/app/shared/forms/form-validators/video-report.ts [deleted file]
client/src/app/shared/index.ts
client/src/app/shared/shared.module.ts
client/src/app/shared/video-abuse/index.ts [new file with mode: 0644]
client/src/app/shared/video-abuse/video-abuse.model.ts [new file with mode: 0644]
client/src/app/shared/video-abuse/video-abuse.service.ts [new file with mode: 0644]
client/src/app/videos/video-watch/video-report.component.ts
server/initializers/database.js
server/models/video-abuse.js

index ee1c6b12ea591bd60ec3f473bef525f2429dd712..a25f058f8a8f1fd4f75986b54549d38a72d9f1a4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -37,10 +37,6 @@ Prototype of a decentralized video streaming platform using P2P (BitTorrent) dir
     <img src="https://david-dm.org/Chocobozzz/PeerTube/dev-status.svg" alt="devDependency Status" />
   </a>
 
-  <a href="https://codeclimate.com/github/Chocobozzz/PeerTube">
-    <img src="https://codeclimate.com/github/Chocobozzz/PeerTube/badges/gpa.svg" alt="Code climate" />
-  </a>
-
   <a href="http://standardjs.com/">
     <img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg" alt="JavaScript Style Guide" />
   </a>
index 6bff250330e4adeac4c7e3df0748c9526037b46d..cabc6df1577a146476aac642a54a019362c9b027 100644 (file)
@@ -5,6 +5,7 @@ import { AdminComponent } from './admin.component';
 import { FriendsRoutes } from './friends';
 import { RequestsRoutes } from './requests';
 import { UsersRoutes } from './users';
+import { VideoAbusesRoutes } from './video-abuses';
 
 const adminRoutes: Routes = [
   {
@@ -18,7 +19,8 @@ const adminRoutes: Routes = [
       },
       ...FriendsRoutes,
       ...RequestsRoutes,
-      ...UsersRoutes
+      ...UsersRoutes,
+      ...VideoAbusesRoutes
     ]
   }
 ];
index 63d99a3db623b59959969cc9fe8ed788fddd665a..d3ada8ce8aef868c68bb6da048895bfae0d8b4d3 100644 (file)
@@ -5,6 +5,7 @@ import { AdminRoutingModule } from './admin-routing.module';
 import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends';
 import { RequestsComponent, RequestStatsComponent, RequestService } from './requests';
 import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users';
+import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses';
 import { MenuAdminComponent } from './menu-admin.component';
 import { SharedModule } from '../shared';
 
@@ -28,6 +29,9 @@ import { SharedModule } from '../shared';
     UserAddComponent,
     UserListComponent,
 
+    VideoAbusesComponent,
+    VideoAbuseListComponent,
+
     MenuAdminComponent
   ],
 
index e250615aab24e2e2bc134a17ca8939abdd34ceeb..ad7a7a1b4a67d3b4f5c27072d9e025d5cb2c4323 100644 (file)
       <span class="hidden-xs glyphicon glyphicon-stats"></span>
       <a [routerLink]="['/admin/requests/stats']">Request stats</a>
     </div>
+
+    <div id="panel-video-abuses" class="panel-button">
+      <span class="hidden-xs glyphicon glyphicon-alert"></span>
+      <a [routerLink]="['/admin/video-abuses/list']">Video abuses</a>
+    </div>
   </div>
 
   <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 (file)
index 0000000..7f5e65f
--- /dev/null
@@ -0,0 +1,3 @@
+export * from './video-abuse-list';
+export * from './video-abuses.component';
+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 (file)
index 0000000..3f2ed17
--- /dev/null
@@ -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 (file)
index 0000000..4604357
--- /dev/null
@@ -0,0 +1,27 @@
+<h3>Video abuses list</h3>
+
+<table class="table table-hover">
+  <thead>
+    <tr>
+      <th class="cell-id">ID</th>
+      <th class="cell-reason">Reason</th>
+      <th>Reporter pod host</th>
+      <th>Reporter username</th>
+      <th>Video</th>
+      <th>Created at</th>
+    </tr>
+  </thead>
+
+  <tbody>
+    <tr *ngFor="let videoAbuse of videoAbuses">
+      <td>{{ videoAbuse.id }}</td>
+      <td>{{ videoAbuse.reason }}</td>
+      <td>{{ videoAbuse.reporterPodHost }}</td>
+      <td>{{ videoAbuse.reporterUsername }}</td>
+      <td>
+        <a [routerLink]="buildVideoLink(videoAbuse)" title="Go to video">{{ videoAbuse.videoId }}</a>
+      </td>
+      <td>{{ videoAbuse.createdAt | date: 'medium' }}</td>
+    </tr>
+  </tbody>
+</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 (file)
index 0000000..a094f74
--- /dev/null
@@ -0,0 +1,7 @@
+.cell-id {
+  width: 40px;
+}
+
+.cell-reason {
+  width: 200px;
+}
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 (file)
index 0000000..de58bba
--- /dev/null
@@ -0,0 +1,31 @@
+import { setInterval } from 'timers'
+import { Component, OnInit } from '@angular/core';
+
+import { VideoAbuseService, VideoAbuse} from '../../../shared';
+
+@Component({
+       selector: 'my-video-abuse-list',
+       templateUrl: './video-abuse-list.component.html',
+  styleUrls: [ './video-abuse-list.component.scss' ]
+})
+export class VideoAbuseListComponent implements OnInit {
+  videoAbuses: VideoAbuse[];
+
+  constructor(private videoAbuseService: VideoAbuseService) {  }
+
+  ngOnInit() {
+    this.getVideoAbuses();
+  }
+
+  buildVideoLink(videoAbuse: VideoAbuse) {
+    return `/videos/${videoAbuse.videoId}`;
+  }
+
+  private getVideoAbuses() {
+    this.videoAbuseService.getVideoAbuses().subscribe(
+      res => this.videoAbuses = res.videoAbuses,
+
+      err => alert(err.text)
+    );
+  }
+}
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 (file)
index 0000000..001f27e
--- /dev/null
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+  template: '<router-outlet></router-outlet>'
+})
+
+export class VideoAbusesComponent {
+}
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 (file)
index 0000000..26a7618
--- /dev/null
@@ -0,0 +1,28 @@
+import { Routes } from '@angular/router';
+
+import { VideoAbusesComponent } from './video-abuses.component';
+import { VideoAbuseListComponent } from './video-abuse-list';
+
+export const VideoAbusesRoutes: Routes = [
+  {
+      path: 'video-abuses',
+      component: VideoAbusesComponent
+      ,
+      children: [
+        {
+          path: '',
+          redirectTo: 'list',
+          pathMatch: 'full'
+        },
+        {
+          path: 'list',
+          component: VideoAbuseListComponent,
+          data: {
+            meta: {
+              titleSuffix: ' - Video abuses list'
+            }
+          }
+        }
+      ]
+    }
+];
index 119b5d9bf39c6d742b4b50db188f112835d830f4..ab7c2df319441dc18cb76e1dc4b59abed5a19c83 100644 (file)
@@ -1,4 +1,4 @@
 export * from './host.validator';
 export * from './user';
-export * from './video-report';
+export * from './video-abuse';
 export * from './video';
diff --git a/client/src/app/shared/forms/form-validators/video-abuse.ts b/client/src/app/shared/forms/form-validators/video-abuse.ts
new file mode 100644 (file)
index 0000000..94a29a3
--- /dev/null
@@ -0,0 +1,10 @@
+import { Validators } from '@angular/forms';
+
+export const VIDEO_ABUSE_REASON = {
+  VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ],
+  MESSAGES: {
+    'required': 'Report reason name is required.',
+    'minlength': 'Report reson must be at least 2 characters long.',
+    'maxlength': 'Report reson cannot be more than 300 characters long.'
+  }
+};
diff --git a/client/src/app/shared/forms/form-validators/video-report.ts b/client/src/app/shared/forms/form-validators/video-report.ts
deleted file mode 100644 (file)
index 036ee17..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Validators } from '@angular/forms';
-
-export const VIDEO_REPORT_REASON = {
-  VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ],
-  MESSAGES: {
-    'required': 'Report reason name is required.',
-    'minlength': 'Report reson must be at least 2 characters long.',
-    'maxlength': 'Report reson cannot be more than 300 characters long.'
-  }
-};
index 52a647b83c1bf5bca8f1928f70dd1146005ff19e..7876e6f140da267f60b7cb3cbc44f205147d0db5 100644 (file)
@@ -3,4 +3,5 @@ export * from './forms';
 export * from './rest';
 export * from './search';
 export * from './users';
+export * from './video-abuse';
 export * from './shared.module';
index 748c5d520956b7a39e32f4ce76afefac212060a4..7b2386d6cf584ec9f3c52487c4e834b1983bd897 100644 (file)
@@ -14,6 +14,7 @@ import { FileUploadModule } from 'ng2-file-upload/ng2-file-upload';
 import { AUTH_HTTP_PROVIDERS } from './auth';
 import { RestExtractor, RestService } from './rest';
 import { SearchComponent, SearchService } from './search';
+import { VideoAbuseService } from './video-abuse';
 
 @NgModule({
   imports: [
@@ -57,7 +58,8 @@ import { SearchComponent, SearchService } from './search';
     AUTH_HTTP_PROVIDERS,
     RestExtractor,
     RestService,
-    SearchService
+    SearchService,
+    VideoAbuseService
   ]
 })
 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 (file)
index 0000000..563533b
--- /dev/null
@@ -0,0 +1,2 @@
+export * from './video-abuse.service';
+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 (file)
index 0000000..bb03730
--- /dev/null
@@ -0,0 +1,8 @@
+export interface VideoAbuse {
+  id: string;
+  reason: string;
+  reporterPodHost: string;
+  reporterUsername: string;
+  videoId: string;
+  createdAt: Date;
+}
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 (file)
index 0000000..2750a41
--- /dev/null
@@ -0,0 +1,44 @@
+import { Injectable } from '@angular/core';
+import { Http } from '@angular/http';
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/map';
+
+import { AuthService } from '../core';
+import { AuthHttp } from '../auth';
+import { RestExtractor, ResultList } from '../rest';
+import { VideoAbuse } from './video-abuse.model';
+
+@Injectable()
+export class VideoAbuseService {
+  private static BASE_VIDEO_ABUSE_URL = '/api/v1/videos/';
+
+  constructor(
+    private authHttp: AuthHttp,
+    private restExtractor: RestExtractor
+  ) {}
+
+  getVideoAbuses() {
+    return this.authHttp.get(VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse')
+                        .map(this.restExtractor.extractDataList)
+                        .map(this.extractVideoAbuses)
+  }
+
+  reportVideo(id: string, reason: string) {
+    const body = {
+      reason
+    };
+    const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse';
+
+    return this.authHttp.post(url, body)
+                        .map(this.restExtractor.extractDataBool)
+                        .catch((res) => this.restExtractor.handleError(res));
+  }
+
+  private extractVideoAbuses(result: ResultList) {
+    const videoAbuses: VideoAbuse[] = result.data;
+    const totalVideoAbuses = result.total;
+
+    return { videoAbuses, totalVideoAbuses };
+  }
+}
index 7bc1677abceab356c16809fe9c32db6d32fe19d5..7a125f53e573dd548c7d9fca9a79ecd7d038f119 100644 (file)
@@ -3,7 +3,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
 
 import { ModalDirective } from 'ng2-bootstrap/modal';
 
-import { FormReactive, VIDEO_REPORT_REASON } from '../../shared';
+import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared';
 import { Video, VideoService } from '../shared';
 
 @Component({
@@ -21,12 +21,12 @@ export class VideoReportComponent extends FormReactive implements OnInit {
     reason: ''
   };
   validationMessages = {
-    reason: VIDEO_REPORT_REASON.MESSAGES
+    reason: VIDEO_ABUSE_REASON.MESSAGES
   };
 
   constructor(
     private formBuilder: FormBuilder,
-    private videoService: VideoService
+    private videoAbuseService: VideoAbuseService
    ) {
     super();
   }
@@ -37,7 +37,7 @@ export class VideoReportComponent extends FormReactive implements OnInit {
 
   buildForm() {
     this.form = this.formBuilder.group({
-      reason: [ '', VIDEO_REPORT_REASON.VALIDATORS ]
+      reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ]
     });
 
     this.form.valueChanges.subscribe(data => this.onValueChanged(data));
@@ -54,7 +54,7 @@ export class VideoReportComponent extends FormReactive implements OnInit {
   report() {
     const reason = this.form.value['reason']
 
-    this.videoService.reportVideo(this.video.id, reason)
+    this.videoAbuseService.reportVideo(this.video.id, reason)
                      .subscribe(
                        // TODO: move alert to beautiful notifications
                        ok => {
index f8f68adebb90e85f1a149500b010f3c74d0497af..043152a0e33f95ac389f017b97e6cd10487efe43 100644 (file)
@@ -70,7 +70,7 @@ function init (silent, callback) {
       }
     })
 
-    if (!silent) logger.info('Database is ready.')
+    if (!silent) logger.info('Database %s is ready.', dbname)
 
     return callback(null)
   })
index 766a7568da75b090deae447576754647bb59a50e..67cead3afd05f4cf531624d70cf433598055963b 100644 (file)
@@ -106,7 +106,8 @@ function toFormatedJSON () {
     reporterPodHost,
     reason: this.reason,
     reporterUsername: this.reporterUsername,
-    videoId: this.videoId
+    videoId: this.videoId,
+    createdAt: this.createdAt
   }
 
   return json