Client: add basic support to report video abuses
This commit is contained in:
parent
4f8c0eb0e9
commit
11ac88de40
|
@ -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" />
|
<img src="https://david-dm.org/Chocobozzz/PeerTube/dev-status.svg" alt="devDependency Status" />
|
||||||
</a>
|
</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/">
|
<a href="http://standardjs.com/">
|
||||||
<img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg" alt="JavaScript Style Guide" />
|
<img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg" alt="JavaScript Style Guide" />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { AdminComponent } from './admin.component';
|
||||||
import { FriendsRoutes } from './friends';
|
import { FriendsRoutes } from './friends';
|
||||||
import { RequestsRoutes } from './requests';
|
import { RequestsRoutes } from './requests';
|
||||||
import { UsersRoutes } from './users';
|
import { UsersRoutes } from './users';
|
||||||
|
import { VideoAbusesRoutes } from './video-abuses';
|
||||||
|
|
||||||
const adminRoutes: Routes = [
|
const adminRoutes: Routes = [
|
||||||
{
|
{
|
||||||
|
@ -18,7 +19,8 @@ const adminRoutes: Routes = [
|
||||||
},
|
},
|
||||||
...FriendsRoutes,
|
...FriendsRoutes,
|
||||||
...RequestsRoutes,
|
...RequestsRoutes,
|
||||||
...UsersRoutes
|
...UsersRoutes,
|
||||||
|
...VideoAbusesRoutes
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { AdminRoutingModule } from './admin-routing.module';
|
||||||
import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends';
|
import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends';
|
||||||
import { RequestsComponent, RequestStatsComponent, RequestService } from './requests';
|
import { RequestsComponent, RequestStatsComponent, RequestService } from './requests';
|
||||||
import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users';
|
import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users';
|
||||||
|
import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses';
|
||||||
import { MenuAdminComponent } from './menu-admin.component';
|
import { MenuAdminComponent } from './menu-admin.component';
|
||||||
import { SharedModule } from '../shared';
|
import { SharedModule } from '../shared';
|
||||||
|
|
||||||
|
@ -28,6 +29,9 @@ import { SharedModule } from '../shared';
|
||||||
UserAddComponent,
|
UserAddComponent,
|
||||||
UserListComponent,
|
UserListComponent,
|
||||||
|
|
||||||
|
VideoAbusesComponent,
|
||||||
|
VideoAbuseListComponent,
|
||||||
|
|
||||||
MenuAdminComponent
|
MenuAdminComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
<span class="hidden-xs glyphicon glyphicon-stats"></span>
|
<span class="hidden-xs glyphicon glyphicon-stats"></span>
|
||||||
<a [routerLink]="['/admin/requests/stats']">Request stats</a>
|
<a [routerLink]="['/admin/requests/stats']">Request stats</a>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div class="panel-block">
|
<div class="panel-block">
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
export * from './video-abuse-list';
|
||||||
|
export * from './video-abuses.component';
|
||||||
|
export * from './video-abuses.routes';
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './video-abuse-list.component';
|
|
@ -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>
|
|
@ -0,0 +1,7 @@
|
||||||
|
.cell-id {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-reason {
|
||||||
|
width: 200px;
|
||||||
|
}
|
|
@ -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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: '<router-outlet></router-outlet>'
|
||||||
|
})
|
||||||
|
|
||||||
|
export class VideoAbusesComponent {
|
||||||
|
}
|
|
@ -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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
|
@ -1,4 +1,4 @@
|
||||||
export * from './host.validator';
|
export * from './host.validator';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
export * from './video-report';
|
export * from './video-abuse';
|
||||||
export * from './video';
|
export * from './video';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Validators } from '@angular/forms';
|
import { Validators } from '@angular/forms';
|
||||||
|
|
||||||
export const VIDEO_REPORT_REASON = {
|
export const VIDEO_ABUSE_REASON = {
|
||||||
VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ],
|
VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ],
|
||||||
MESSAGES: {
|
MESSAGES: {
|
||||||
'required': 'Report reason name is required.',
|
'required': 'Report reason name is required.',
|
|
@ -3,4 +3,5 @@ export * from './forms';
|
||||||
export * from './rest';
|
export * from './rest';
|
||||||
export * from './search';
|
export * from './search';
|
||||||
export * from './users';
|
export * from './users';
|
||||||
|
export * from './video-abuse';
|
||||||
export * from './shared.module';
|
export * from './shared.module';
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { FileUploadModule } from 'ng2-file-upload/ng2-file-upload';
|
||||||
import { AUTH_HTTP_PROVIDERS } from './auth';
|
import { AUTH_HTTP_PROVIDERS } from './auth';
|
||||||
import { RestExtractor, RestService } from './rest';
|
import { RestExtractor, RestService } from './rest';
|
||||||
import { SearchComponent, SearchService } from './search';
|
import { SearchComponent, SearchService } from './search';
|
||||||
|
import { VideoAbuseService } from './video-abuse';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -57,7 +58,8 @@ import { SearchComponent, SearchService } from './search';
|
||||||
AUTH_HTTP_PROVIDERS,
|
AUTH_HTTP_PROVIDERS,
|
||||||
RestExtractor,
|
RestExtractor,
|
||||||
RestService,
|
RestService,
|
||||||
SearchService
|
SearchService,
|
||||||
|
VideoAbuseService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule { }
|
export class SharedModule { }
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './video-abuse.service';
|
||||||
|
export * from './video-abuse.model';
|
|
@ -0,0 +1,8 @@
|
||||||
|
export interface VideoAbuse {
|
||||||
|
id: string;
|
||||||
|
reason: string;
|
||||||
|
reporterPodHost: string;
|
||||||
|
reporterUsername: string;
|
||||||
|
videoId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
}
|
|
@ -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 };
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
import { ModalDirective } from 'ng2-bootstrap/modal';
|
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';
|
import { Video, VideoService } from '../shared';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -21,12 +21,12 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
||||||
reason: ''
|
reason: ''
|
||||||
};
|
};
|
||||||
validationMessages = {
|
validationMessages = {
|
||||||
reason: VIDEO_REPORT_REASON.MESSAGES
|
reason: VIDEO_ABUSE_REASON.MESSAGES
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private videoService: VideoService
|
private videoAbuseService: VideoAbuseService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
||||||
|
|
||||||
buildForm() {
|
buildForm() {
|
||||||
this.form = this.formBuilder.group({
|
this.form = this.formBuilder.group({
|
||||||
reason: [ '', VIDEO_REPORT_REASON.VALIDATORS ]
|
reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.valueChanges.subscribe(data => this.onValueChanged(data));
|
this.form.valueChanges.subscribe(data => this.onValueChanged(data));
|
||||||
|
@ -54,7 +54,7 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
||||||
report() {
|
report() {
|
||||||
const reason = this.form.value['reason']
|
const reason = this.form.value['reason']
|
||||||
|
|
||||||
this.videoService.reportVideo(this.video.id, reason)
|
this.videoAbuseService.reportVideo(this.video.id, reason)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
// TODO: move alert to beautiful notifications
|
// TODO: move alert to beautiful notifications
|
||||||
ok => {
|
ok => {
|
||||||
|
|
|
@ -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)
|
return callback(null)
|
||||||
})
|
})
|
||||||
|
|
|
@ -106,7 +106,8 @@ function toFormatedJSON () {
|
||||||
reporterPodHost,
|
reporterPodHost,
|
||||||
reason: this.reason,
|
reason: this.reason,
|
||||||
reporterUsername: this.reporterUsername,
|
reporterUsername: this.reporterUsername,
|
||||||
videoId: this.videoId
|
videoId: this.videoId,
|
||||||
|
createdAt: this.createdAt
|
||||||
}
|
}
|
||||||
|
|
||||||
return json
|
return json
|
||||||
|
|
Loading…
Reference in New Issue