Client: add ability to report a video
This commit is contained in:
parent
872a4c7cea
commit
4f8c0eb0e9
|
@ -1,3 +1,4 @@
|
||||||
export * from './host.validator';
|
export * from './host.validator';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
|
export * from './video-report';
|
||||||
export * from './video';
|
export * from './video';
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
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.'
|
||||||
|
}
|
||||||
|
};
|
|
@ -55,6 +55,17 @@ export class VideoService {
|
||||||
.catch((res) => this.restExtractor.handleError(res));
|
.catch((res) => this.restExtractor.handleError(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reportVideo(id: string, reason: string) {
|
||||||
|
const body = {
|
||||||
|
reason
|
||||||
|
};
|
||||||
|
const url = VideoService.BASE_VIDEO_URL + id + '/abuse';
|
||||||
|
|
||||||
|
return this.authHttp.post(url, body)
|
||||||
|
.map(this.restExtractor.extractDataBool)
|
||||||
|
.catch((res) => this.restExtractor.handleError(res));
|
||||||
|
}
|
||||||
|
|
||||||
private extractVideos(result: ResultList) {
|
private extractVideos(result: ResultList) {
|
||||||
const videosJson = result.data;
|
const videosJson = result.data;
|
||||||
const totalVideos = result.total;
|
const totalVideos = result.total;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './video-magnet.component';
|
export * from './video-magnet.component';
|
||||||
export * from './video-share.component';
|
export * from './video-share.component';
|
||||||
|
export * from './video-report.component';
|
||||||
export * from './video-watch.component';
|
export * from './video-watch.component';
|
||||||
export * from './webtorrent.service';
|
export * from './webtorrent.service';
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<div bsModal #modal="bs-modal" class="modal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content modal-lg">
|
||||||
|
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="hide()">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title">Report video</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<form novalidate [formGroup]="form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description">Reason</label>
|
||||||
|
<textarea
|
||||||
|
id="reason" class="form-control" placeholder="Reason..."
|
||||||
|
formControlName="reason"
|
||||||
|
>
|
||||||
|
</textarea>
|
||||||
|
<div *ngIf="formErrors.reason" class="alert alert-danger">
|
||||||
|
{{ formErrors.reason }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="button" value="Report" class="btn btn-default form-control"
|
||||||
|
[disabled]="!form.valid" (click)="report()"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,68 @@
|
||||||
|
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
import { ModalDirective } from 'ng2-bootstrap/modal';
|
||||||
|
|
||||||
|
import { FormReactive, VIDEO_REPORT_REASON } from '../../shared';
|
||||||
|
import { Video, VideoService } from '../shared';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-video-report',
|
||||||
|
templateUrl: './video-report.component.html'
|
||||||
|
})
|
||||||
|
export class VideoReportComponent extends FormReactive implements OnInit {
|
||||||
|
@Input() video: Video = null;
|
||||||
|
|
||||||
|
@ViewChild('modal') modal: ModalDirective;
|
||||||
|
|
||||||
|
error: string = null;
|
||||||
|
form: FormGroup;
|
||||||
|
formErrors = {
|
||||||
|
reason: ''
|
||||||
|
};
|
||||||
|
validationMessages = {
|
||||||
|
reason: VIDEO_REPORT_REASON.MESSAGES
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private videoService: VideoService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.buildForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
buildForm() {
|
||||||
|
this.form = this.formBuilder.group({
|
||||||
|
reason: [ '', VIDEO_REPORT_REASON.VALIDATORS ]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.form.valueChanges.subscribe(data => this.onValueChanged(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.modal.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
report() {
|
||||||
|
const reason = this.form.value['reason']
|
||||||
|
|
||||||
|
this.videoService.reportVideo(this.video.id, reason)
|
||||||
|
.subscribe(
|
||||||
|
// TODO: move alert to beautiful notifications
|
||||||
|
ok => {
|
||||||
|
alert('Video reported.');
|
||||||
|
this.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
err => alert(err.text)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,6 +60,19 @@
|
||||||
<button title="Get magnet URI" id="magnet-uri" class="btn btn-default" (click)="showMagnetUriModal()">
|
<button title="Get magnet URI" id="magnet-uri" class="btn btn-default" (click)="showMagnetUriModal()">
|
||||||
<span class="glyphicon glyphicon-magnet"></span> Magnet
|
<span class="glyphicon glyphicon-magnet"></span> Magnet
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div *ngIf="isUserLoggedIn()" class="btn-group" dropdown>
|
||||||
|
<button id="single-button" type="button" id="more" class="btn btn-default" dropdownToggle>
|
||||||
|
<span class="glyphicon glyphicon-option-horizontal"></span> More
|
||||||
|
</button>
|
||||||
|
<ul dropdownMenu id="more-menu" role="menu" aria-labelledby="single-button">
|
||||||
|
<li role="menuitem">
|
||||||
|
<a class="dropdown-item" href="#" (click)="showReportModal($event)">
|
||||||
|
<span class="glyphicon glyphicon-alert"></span> Report
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -79,5 +92,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<my-video-share #videoShareModal *ngIf="video !== null" [video]="video"></my-video-share>
|
<template [ngIf]="video !== null">
|
||||||
<my-video-magnet #videoMagnetModal *ngIf="video !== null" [video]="video"></my-video-magnet>
|
<my-video-share #videoShareModal [video]="video"></my-video-share>
|
||||||
|
<my-video-magnet #videoMagnetModal [video]="video"></my-video-magnet>
|
||||||
|
<my-video-report #videoReportModal [video]="video"></my-video-report>
|
||||||
|
</template>
|
||||||
|
|
|
@ -47,10 +47,14 @@
|
||||||
top: 2px;
|
top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#magnet-uri, #share {
|
#magnet-uri, #share, #more {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#more-menu .dropdown-item .glyphicon {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#video-by-date {
|
#video-by-date {
|
||||||
|
|
|
@ -5,8 +5,10 @@ import { ActivatedRoute } from '@angular/router';
|
||||||
import { MetaService } from 'ng2-meta';
|
import { MetaService } from 'ng2-meta';
|
||||||
import * as videojs from 'video.js';
|
import * as videojs from 'video.js';
|
||||||
|
|
||||||
|
import { AuthService } from '../../core';
|
||||||
import { VideoMagnetComponent } from './video-magnet.component';
|
import { VideoMagnetComponent } from './video-magnet.component';
|
||||||
import { VideoShareComponent } from './video-share.component';
|
import { VideoShareComponent } from './video-share.component';
|
||||||
|
import { VideoReportComponent } from './video-report.component';
|
||||||
import { Video, VideoService } from '../shared';
|
import { Video, VideoService } from '../shared';
|
||||||
import { WebTorrentService } from './webtorrent.service';
|
import { WebTorrentService } from './webtorrent.service';
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent;
|
@ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent;
|
||||||
@ViewChild('videoShareModal') videoShareModal: VideoShareComponent;
|
@ViewChild('videoShareModal') videoShareModal: VideoShareComponent;
|
||||||
|
@ViewChild('videoReportModal') videoReportModal: VideoReportComponent;
|
||||||
|
|
||||||
downloadSpeed: number;
|
downloadSpeed: number;
|
||||||
error: boolean = false;
|
error: boolean = false;
|
||||||
|
@ -42,7 +45,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private videoService: VideoService,
|
private videoService: VideoService,
|
||||||
private metaService: MetaService,
|
private metaService: MetaService,
|
||||||
private webTorrentService: WebTorrentService
|
private webTorrentService: WebTorrentService,
|
||||||
|
private authService: AuthService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -123,6 +127,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showReportModal(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.videoReportModal.show();
|
||||||
|
}
|
||||||
|
|
||||||
showShareModal() {
|
showShareModal() {
|
||||||
this.videoShareModal.show();
|
this.videoShareModal.show();
|
||||||
}
|
}
|
||||||
|
@ -131,6 +140,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
this.videoMagnetModal.show();
|
this.videoMagnetModal.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isUserLoggedIn() {
|
||||||
|
return this.authService.isLoggedIn();
|
||||||
|
}
|
||||||
|
|
||||||
private loadTooLong() {
|
private loadTooLong() {
|
||||||
this.error = true;
|
this.error = true;
|
||||||
console.error('The video load seems to be abnormally long.');
|
console.error('The video load seems to be abnormally long.');
|
||||||
|
|
|
@ -4,7 +4,13 @@ import { VideosRoutingModule } from './videos-routing.module';
|
||||||
import { VideosComponent } from './videos.component';
|
import { VideosComponent } from './videos.component';
|
||||||
import { VideoAddComponent } from './video-add';
|
import { VideoAddComponent } from './video-add';
|
||||||
import { VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list';
|
import { VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list';
|
||||||
import { VideoWatchComponent, VideoMagnetComponent, VideoShareComponent, WebTorrentService } from './video-watch';
|
import {
|
||||||
|
VideoWatchComponent,
|
||||||
|
VideoMagnetComponent,
|
||||||
|
VideoReportComponent,
|
||||||
|
VideoShareComponent,
|
||||||
|
WebTorrentService
|
||||||
|
} from './video-watch';
|
||||||
import { LoaderComponent, VideoService } from './shared';
|
import { LoaderComponent, VideoService } from './shared';
|
||||||
import { SharedModule } from '../shared';
|
import { SharedModule } from '../shared';
|
||||||
|
|
||||||
|
@ -26,6 +32,7 @@ import { SharedModule } from '../shared';
|
||||||
VideoWatchComponent,
|
VideoWatchComponent,
|
||||||
VideoMagnetComponent,
|
VideoMagnetComponent,
|
||||||
VideoShareComponent,
|
VideoShareComponent,
|
||||||
|
VideoReportComponent,
|
||||||
|
|
||||||
LoaderComponent
|
LoaderComponent
|
||||||
],
|
],
|
||||||
|
|
|
@ -61,7 +61,6 @@ function transactionRetryer (func, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function startSerializableTransaction (callback) {
|
function startSerializableTransaction (callback) {
|
||||||
console.log(db)
|
|
||||||
db.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err, t) {
|
db.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err, t) {
|
||||||
// We force to return only two parameters
|
// We force to return only two parameters
|
||||||
return callback(err, t)
|
return callback(err, t)
|
||||||
|
|
Loading…
Reference in New Issue