Client: add basic support to report video abuses

pull/40/head
Chocobozzz 2017-01-23 22:16:48 +01:00
parent 4f8c0eb0e9
commit 11ac88de40
21 changed files with 185 additions and 15 deletions

View File

@ -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>

View 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
]
}
];

View 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
],

View File

@ -15,6 +15,11 @@
<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">

View File

@ -0,0 +1,3 @@
export * from './video-abuse-list';
export * from './video-abuses.component';
export * from './video-abuses.routes';

View File

@ -0,0 +1 @@
export * from './video-abuse-list.component';

View File

@ -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>

View File

@ -0,0 +1,7 @@
.cell-id {
width: 40px;
}
.cell-reason {
width: 200px;
}

View File

@ -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)
);
}
}

View File

@ -0,0 +1,8 @@
import { Component } from '@angular/core';
@Component({
template: '<router-outlet></router-outlet>'
})
export class VideoAbusesComponent {
}

View File

@ -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'
}
}
}
]
}
];

View File

@ -1,4 +1,4 @@
export * from './host.validator';
export * from './user';
export * from './video-report';
export * from './video-abuse';
export * from './video';

View File

@ -1,6 +1,6 @@
import { Validators } from '@angular/forms';
export const VIDEO_REPORT_REASON = {
export const VIDEO_ABUSE_REASON = {
VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ],
MESSAGES: {
'required': 'Report reason name is required.',

View 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';

View 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 { }

View File

@ -0,0 +1,2 @@
export * from './video-abuse.service';
export * from './video-abuse.model';

View File

@ -0,0 +1,8 @@
export interface VideoAbuse {
id: string;
reason: string;
reporterPodHost: string;
reporterUsername: string;
videoId: string;
createdAt: Date;
}

View File

@ -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 };
}
}

View 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 => {

View 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)
})

View 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