diff --git a/client/src/app/shared/forms/form-validators/index.ts b/client/src/app/shared/forms/form-validators/index.ts
index 4c6cc6637..119b5d9bf 100644
--- a/client/src/app/shared/forms/form-validators/index.ts
+++ b/client/src/app/shared/forms/form-validators/index.ts
@@ -1,3 +1,4 @@
export * from './host.validator';
export * from './user';
+export * from './video-report';
export * from './video';
diff --git a/client/src/app/shared/forms/form-validators/video-report.ts b/client/src/app/shared/forms/form-validators/video-report.ts
new file mode 100644
index 000000000..036ee1721
--- /dev/null
+++ b/client/src/app/shared/forms/form-validators/video-report.ts
@@ -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.'
+ }
+};
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts
index 9d79b2f5e..7094d9a34 100644
--- a/client/src/app/videos/shared/video.service.ts
+++ b/client/src/app/videos/shared/video.service.ts
@@ -55,6 +55,17 @@ export class VideoService {
.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;
diff --git a/client/src/app/videos/video-watch/index.ts b/client/src/app/videos/video-watch/index.ts
index 1a8403b0a..ed0ed2fc0 100644
--- a/client/src/app/videos/video-watch/index.ts
+++ b/client/src/app/videos/video-watch/index.ts
@@ -1,4 +1,5 @@
export * from './video-magnet.component';
export * from './video-share.component';
+export * from './video-report.component';
export * from './video-watch.component';
export * from './webtorrent.service';
diff --git a/client/src/app/videos/video-watch/video-report.component.html b/client/src/app/videos/video-watch/video-report.component.html
new file mode 100644
index 000000000..741080ead
--- /dev/null
+++ b/client/src/app/videos/video-watch/video-report.component.html
@@ -0,0 +1,38 @@
+
diff --git a/client/src/app/videos/video-watch/video-report.component.ts b/client/src/app/videos/video-watch/video-report.component.ts
new file mode 100644
index 000000000..7bc1677ab
--- /dev/null
+++ b/client/src/app/videos/video-watch/video-report.component.ts
@@ -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)
+ )
+ }
+}
diff --git a/client/src/app/videos/video-watch/video-watch.component.html b/client/src/app/videos/video-watch/video-watch.component.html
index a726ef3ff..8cee9959d 100644
--- a/client/src/app/videos/video-watch/video-watch.component.html
+++ b/client/src/app/videos/video-watch/video-watch.component.html
@@ -60,6 +60,19 @@
+
+
+
+
+
@@ -79,5 +92,8 @@
-
-
+
+
+
+
+
diff --git a/client/src/app/videos/video-watch/video-watch.component.scss b/client/src/app/videos/video-watch/video-watch.component.scss
index ac62b04e7..794412707 100644
--- a/client/src/app/videos/video-watch/video-watch.component.scss
+++ b/client/src/app/videos/video-watch/video-watch.component.scss
@@ -47,10 +47,14 @@
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 {
diff --git a/client/src/app/videos/video-watch/video-watch.component.ts b/client/src/app/videos/video-watch/video-watch.component.ts
index 256ffef99..d83cc5a7a 100644
--- a/client/src/app/videos/video-watch/video-watch.component.ts
+++ b/client/src/app/videos/video-watch/video-watch.component.ts
@@ -5,8 +5,10 @@ import { ActivatedRoute } from '@angular/router';
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';
@@ -21,6 +23,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
@ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent;
@ViewChild('videoShareModal') videoShareModal: VideoShareComponent;
+ @ViewChild('videoReportModal') videoReportModal: VideoReportComponent;
downloadSpeed: number;
error: boolean = false;
@@ -42,7 +45,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private videoService: VideoService,
private metaService: MetaService,
- private webTorrentService: WebTorrentService
+ private webTorrentService: WebTorrentService,
+ private authService: AuthService
) {}
ngOnInit() {
@@ -123,6 +127,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
});
}
+ showReportModal(event: Event) {
+ event.preventDefault();
+ this.videoReportModal.show();
+ }
+
showShareModal() {
this.videoShareModal.show();
}
@@ -131,6 +140,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.videoMagnetModal.show();
}
+ isUserLoggedIn() {
+ return this.authService.isLoggedIn();
+ }
+
private loadTooLong() {
this.error = true;
console.error('The video load seems to be abnormally long.');
diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts
index fb2f453b0..03dea17b5 100644
--- a/client/src/app/videos/videos.module.ts
+++ b/client/src/app/videos/videos.module.ts
@@ -4,7 +4,13 @@ import { VideosRoutingModule } from './videos-routing.module';
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';
@@ -26,6 +32,7 @@ import { SharedModule } from '../shared';
VideoWatchComponent,
VideoMagnetComponent,
VideoShareComponent,
+ VideoReportComponent,
LoaderComponent
],
diff --git a/server/helpers/database-utils.js b/server/helpers/database-utils.js
index 6fe7e99aa..c72d19429 100644
--- a/server/helpers/database-utils.js
+++ b/server/helpers/database-utils.js
@@ -61,7 +61,6 @@ function transactionRetryer (func, callback) {
}
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)