export * from './host.validator';
export * from './user';
+export * from './video-report';
export * from './video';
--- /dev/null
+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.'
+ }
+};
.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) {
const videosJson = result.data;
const totalVideos = result.total;
export * from './video-magnet.component';
export * from './video-share.component';
+export * from './video-report.component';
export * from './video-watch.component';
export * from './webtorrent.service';
--- /dev/null
+<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>
--- /dev/null
+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)
+ )
+ }
+}
<button title="Get magnet URI" id="magnet-uri" class="btn btn-default" (click)="showMagnetUriModal()">
<span class="glyphicon glyphicon-magnet"></span> Magnet
</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>
-<my-video-share #videoShareModal *ngIf="video !== null" [video]="video"></my-video-share>
-<my-video-magnet #videoMagnetModal *ngIf="video !== null" [video]="video"></my-video-magnet>
+<template [ngIf]="video !== null">
+ <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>
top: 2px;
}
- #magnet-uri, #share {
+ #magnet-uri, #share, #more {
font-weight: bold;
opacity: 0.85;
}
+
+ #more-menu .dropdown-item .glyphicon {
+ margin-right: 5px;
+ }
}
#video-by-date {
import { MetaService } from 'ng2-meta';
import * as videojs from 'video.js';
+import { AuthService } from '../../core';
import { VideoMagnetComponent } from './video-magnet.component';
import { VideoShareComponent } from './video-share.component';
+import { VideoReportComponent } from './video-report.component';
import { Video, VideoService } from '../shared';
import { WebTorrentService } from './webtorrent.service';
@ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent;
@ViewChild('videoShareModal') videoShareModal: VideoShareComponent;
+ @ViewChild('videoReportModal') videoReportModal: VideoReportComponent;
downloadSpeed: number;
error: boolean = false;
private route: ActivatedRoute,
private videoService: VideoService,
private metaService: MetaService,
- private webTorrentService: WebTorrentService
+ private webTorrentService: WebTorrentService,
+ private authService: AuthService
) {}
ngOnInit() {
});
}
+ showReportModal(event: Event) {
+ event.preventDefault();
+ this.videoReportModal.show();
+ }
+
showShareModal() {
this.videoShareModal.show();
}
this.videoMagnetModal.show();
}
+ isUserLoggedIn() {
+ return this.authService.isLoggedIn();
+ }
+
private loadTooLong() {
this.error = true;
console.error('The video load seems to be abnormally long.');
import { VideosComponent } from './videos.component';
import { VideoAddComponent } from './video-add';
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 { SharedModule } from '../shared';
VideoWatchComponent,
VideoMagnetComponent,
VideoShareComponent,
+ VideoReportComponent,
LoaderComponent
],
}
function startSerializableTransaction (callback) {
- console.log(db)
db.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err, t) {
// We force to return only two parameters
return callback(err, t)