From d8e689b864749648d03cf4391fd4a475126f01cd Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 10 Apr 2017 21:15:28 +0200 Subject: [PATCH] Client: add basic support for updating a video --- client/src/app/videos/index.ts | 2 +- client/src/app/videos/shared/video.model.ts | 38 ++++ client/src/app/videos/shared/video.service.ts | 19 +- client/src/app/videos/video-add/index.ts | 1 - client/src/app/videos/video-edit/index.ts | 2 + .../video-add.component.html | 0 .../video-add.component.ts | 2 +- .../video-edit.component.scss} | 0 .../video-edit/video-update.component.html | 101 +++++++++++ .../video-edit/video-update.component.ts | 170 ++++++++++++++++++ .../video-watch/video-watch.component.html | 6 + .../video-watch/video-watch.component.ts | 5 + .../src/app/videos/videos-routing.module.ts | 11 +- client/src/app/videos/videos.module.ts | 3 +- 14 files changed, 354 insertions(+), 6 deletions(-) delete mode 100644 client/src/app/videos/video-add/index.ts create mode 100644 client/src/app/videos/video-edit/index.ts rename client/src/app/videos/{video-add => video-edit}/video-add.component.html (100%) rename client/src/app/videos/{video-add => video-edit}/video-add.component.ts (99%) rename client/src/app/videos/{video-add/video-add.component.scss => video-edit/video-edit.component.scss} (100%) create mode 100644 client/src/app/videos/video-edit/video-update.component.html create mode 100644 client/src/app/videos/video-edit/video-update.component.ts diff --git a/client/src/app/videos/index.ts b/client/src/app/videos/index.ts index ca386a51d..5158a23f8 100644 --- a/client/src/app/videos/index.ts +++ b/client/src/app/videos/index.ts @@ -1,5 +1,5 @@ export * from './shared'; -export * from './video-add'; +export * from './video-edit'; export * from './video-list'; export * from './video-watch'; export * from './videos-routing.module'; diff --git a/client/src/app/videos/shared/video.model.ts b/client/src/app/videos/shared/video.model.ts index f135ca707..404e3bf45 100644 --- a/client/src/app/videos/shared/video.model.ts +++ b/client/src/app/videos/shared/video.model.ts @@ -5,8 +5,11 @@ export class Video { by: string; createdAt: Date; categoryLabel: string; + category: string; licenceLabel: string; + licence: string; languageLabel: string; + language: string; description: string; duration: string; id: string; @@ -38,8 +41,11 @@ export class Video { author: string, createdAt: string, categoryLabel: string, + category: string, licenceLabel: string, + licence: string, languageLabel: string; + language: string; description: string, duration: number; id: string, @@ -57,8 +63,11 @@ export class Video { this.author = hash.author; this.createdAt = new Date(hash.createdAt); this.categoryLabel = hash.categoryLabel; + this.category = hash.category; this.licenceLabel = hash.licenceLabel; + this.licence = hash.licence; this.languageLabel = hash.languageLabel; + this.language = hash.language; this.description = hash.description; this.duration = Video.createDurationString(hash.duration); this.id = hash.id; @@ -84,4 +93,33 @@ export class Video { // If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos... return (this.nsfw && (!user || user.displayNSFW === false)); } + + patch(values: Object) { + Object.keys(values).forEach((key) => { + this[key] = values[key]; + }); + } + + toJSON() { + return { + author: this.author, + createdAt: this.createdAt, + category: this.category, + licence: this.licence, + language: this.language, + description: this.description, + duration: this.duration, + id: this.id, + isLocal: this.isLocal, + magnetUri: this.magnetUri, + name: this.name, + podHost: this.podHost, + tags: this.tags, + thumbnailPath: this.thumbnailPath, + views: this.views, + likes: this.likes, + dislikes: this.dislikes, + nsfw: this.nsfw + }; + } } diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts index 13d4ca246..ee67bc1ae 100644 --- a/client/src/app/videos/shared/video.service.ts +++ b/client/src/app/videos/shared/video.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { Http } from '@angular/http'; +import { Http, Headers, RequestOptions } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; import 'rxjs/add/operator/map'; @@ -80,6 +80,23 @@ export class VideoService { .catch((res) => this.restExtractor.handleError(res)); } + updateVideo(video: Video) { + const body = { + name: video.name, + category: video.category, + licence: video.licence, + language: video.language, + description: video.description, + tags: video.tags + }; + const headers = new Headers({ 'Content-Type': 'application/json' }); + const options = new RequestOptions({ headers: headers }); + + return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body, options) + .map(this.restExtractor.extractDataBool) + .catch(this.restExtractor.handleError); + } + getVideos(pagination: RestPagination, sort: SortField) { const params = this.restService.buildRestGetParams(pagination, sort); diff --git a/client/src/app/videos/video-add/index.ts b/client/src/app/videos/video-add/index.ts deleted file mode 100644 index 79488e851..000000000 --- a/client/src/app/videos/video-add/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './video-add.component'; diff --git a/client/src/app/videos/video-edit/index.ts b/client/src/app/videos/video-edit/index.ts new file mode 100644 index 000000000..5ce4fb9b1 --- /dev/null +++ b/client/src/app/videos/video-edit/index.ts @@ -0,0 +1,2 @@ +export * from './video-add.component'; +export * from './video-update.component'; diff --git a/client/src/app/videos/video-add/video-add.component.html b/client/src/app/videos/video-edit/video-add.component.html similarity index 100% rename from client/src/app/videos/video-add/video-add.component.html rename to client/src/app/videos/video-edit/video-add.component.html diff --git a/client/src/app/videos/video-add/video-add.component.ts b/client/src/app/videos/video-edit/video-add.component.ts similarity index 99% rename from client/src/app/videos/video-add/video-add.component.ts rename to client/src/app/videos/video-edit/video-add.component.ts index da556f48d..e3cf0e9d8 100644 --- a/client/src/app/videos/video-add/video-add.component.ts +++ b/client/src/app/videos/video-edit/video-add.component.ts @@ -19,7 +19,7 @@ import { VideoService } from '../shared'; @Component({ selector: 'my-videos-add', - styleUrls: [ './video-add.component.scss' ], + styleUrls: [ './video-edit.component.scss' ], templateUrl: './video-add.component.html' }) diff --git a/client/src/app/videos/video-add/video-add.component.scss b/client/src/app/videos/video-edit/video-edit.component.scss similarity index 100% rename from client/src/app/videos/video-add/video-add.component.scss rename to client/src/app/videos/video-edit/video-edit.component.scss diff --git a/client/src/app/videos/video-edit/video-update.component.html b/client/src/app/videos/video-edit/video-update.component.html new file mode 100644 index 000000000..665a952d0 --- /dev/null +++ b/client/src/app/videos/video-edit/video-update.component.html @@ -0,0 +1,101 @@ +

Update {{ video.name }}

+ +
{{ error }}
+ +
+
+ + +
+ {{ formErrors.name }} +
+
+ +
+ + +
+ +
+ + + +
+ {{ formErrors.category }} +
+
+ +
+ + + +
+ {{ formErrors.licence }} +
+
+ +
+ + + +
+ {{ formErrors.language }} +
+
+ +
+ (press enter to add the tag) + +
+ {{ formErrors.currentTag }} +
+
+ +
+
+ {{ tag }} + x +
+
+ +
+ {{ tagsError }} +
+ +
+ + +
+ {{ formErrors.description }} +
+
+ +
+ +
+
diff --git a/client/src/app/videos/video-edit/video-update.component.ts b/client/src/app/videos/video-edit/video-update.component.ts new file mode 100644 index 000000000..b45780a41 --- /dev/null +++ b/client/src/app/videos/video-edit/video-update.component.ts @@ -0,0 +1,170 @@ +import { Component, ElementRef, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { FileUploader } from 'ng2-file-upload/ng2-file-upload'; +import { NotificationsService } from 'angular2-notifications'; + +import { AuthService } from '../../core'; +import { + FormReactive, + VIDEO_NAME, + VIDEO_CATEGORY, + VIDEO_LICENCE, + VIDEO_LANGUAGE, + VIDEO_DESCRIPTION, + VIDEO_TAGS +} from '../../shared'; +import { Video, VideoService } from '../shared'; + +@Component({ + selector: 'my-videos-update', + styleUrls: [ './video-edit.component.scss' ], + templateUrl: './video-update.component.html' +}) + +export class VideoUpdateComponent extends FormReactive implements OnInit { + tags: string[] = []; + videoCategories = []; + videoLicences = []; + videoLanguages = []; + video: Video; + + error: string = null; + form: FormGroup; + formErrors = { + name: '', + category: '', + licence: '', + language: '', + description: '', + currentTag: '' + }; + validationMessages = { + name: VIDEO_NAME.MESSAGES, + category: VIDEO_CATEGORY.MESSAGES, + licence: VIDEO_LICENCE.MESSAGES, + language: VIDEO_LANGUAGE.MESSAGES, + description: VIDEO_DESCRIPTION.MESSAGES, + currentTag: VIDEO_TAGS.MESSAGES + }; + + // Special error messages + tagsError = ''; + fileError = ''; + + constructor( + private authService: AuthService, + private elementRef: ElementRef, + private formBuilder: FormBuilder, + private route: ActivatedRoute, + private router: Router, + private notificationsService: NotificationsService, + private videoService: VideoService + ) { + super(); + } + + buildForm() { + this.form = this.formBuilder.group({ + name: [ '', VIDEO_NAME.VALIDATORS ], + nsfw: [ false ], + category: [ '', VIDEO_CATEGORY.VALIDATORS ], + licence: [ '', VIDEO_LICENCE.VALIDATORS ], + language: [ '', VIDEO_LANGUAGE.VALIDATORS ], + description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], + currentTag: [ '', VIDEO_TAGS.VALIDATORS ] + }); + + this.form.valueChanges.subscribe(data => this.onValueChanged(data)); + } + + ngOnInit() { + this.buildForm(); + + this.videoCategories = this.videoService.videoCategories; + this.videoLicences = this.videoService.videoLicences; + this.videoLanguages = this.videoService.videoLanguages; + + const id = this.route.snapshot.params['id']; + this.videoService.getVideo(id) + .subscribe( + video => { + this.video = video; + + this.hydrateFormFromVideo(); + }, + + err => this.error = 'Cannot fetch video.' + ); + } + + checkForm() { + this.forceCheck(); + + return this.form.valid === true && this.tagsError === '' && this.fileError === ''; + } + + + onTagKeyPress(event: KeyboardEvent) { + // Enter press + if (event.keyCode === 13) { + this.addTagIfPossible(); + } + } + + removeTag(tag: string) { + this.tags.splice(this.tags.indexOf(tag), 1); + this.form.get('currentTag').enable(); + } + + update() { + // Maybe the user forgot to press "enter" when he filled the field + this.addTagIfPossible(); + + if (this.checkForm() === false) { + return; + } + + this.video.patch(this.form.value); + + this.videoService.updateVideo(this.video) + .subscribe( + () => { + this.notificationsService.success('Success', 'Video updated.'); + this.router.navigate([ '/videos/watch', this.video.id ]); + }, + + err => { + this.error = 'Cannot update the video.'; + console.error(err); + } + ); + + } + + private addTagIfPossible() { + const currentTag = this.form.value['currentTag']; + if (currentTag === undefined) return; + + // Check if the tag is valid and does not already exist + if ( + currentTag.length >= 2 && + this.form.controls['currentTag'].valid && + this.tags.indexOf(currentTag) === -1 + ) { + this.tags.push(currentTag); + this.form.patchValue({ currentTag: '' }); + + if (this.tags.length >= 3) { + this.form.get('currentTag').disable(); + } + + this.tagsError = ''; + } + } + + private hydrateFormFromVideo() { + this.form.patchValue(this.video.toJSON()); + } +} 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 a6ec7b20f..2a6b15dc9 100644 --- a/client/src/app/videos/video-watch/video-watch.component.html +++ b/client/src/app/videos/video-watch/video-watch.component.html @@ -79,6 +79,12 @@