From 4f8c0eb0e9356ee2782ea6eb12a92e4dc5f66127 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 20 Jan 2017 19:22:15 +0100 Subject: [PATCH] Client: add ability to report a video --- .../app/shared/forms/form-validators/index.ts | 1 + .../forms/form-validators/video-report.ts | 10 +++ client/src/app/videos/shared/video.service.ts | 11 +++ client/src/app/videos/video-watch/index.ts | 1 + .../video-watch/video-report.component.html | 38 +++++++++++ .../video-watch/video-report.component.ts | 68 +++++++++++++++++++ .../video-watch/video-watch.component.html | 20 +++++- .../video-watch/video-watch.component.scss | 6 +- .../video-watch/video-watch.component.ts | 15 +++- client/src/app/videos/videos.module.ts | 9 ++- server/helpers/database-utils.js | 1 - 11 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 client/src/app/shared/forms/form-validators/video-report.ts create mode 100644 client/src/app/videos/video-watch/video-report.component.html create mode 100644 client/src/app/videos/video-watch/video-report.component.ts 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)