From 1553e15d82b8a1ec4967a90d43b33274f8215c44 Mon Sep 17 00:00:00 2001
From: Chocobozzz <florian.bigard@gmail.com>
Date: Thu, 14 Apr 2016 22:07:46 +0200
Subject: [PATCH] Implement user requests autorizations in the client side

---
 client/angular/app/app.component.ts           |  6 +--
 .../users/components/login/login.component.ts | 17 ++++---
 client/angular/users/models/token.ts          | 24 +++++++--
 client/angular/users/models/user.ts           | 20 ++++++++
 client/angular/users/services/auth.service.ts | 49 ++++++++++++++++---
 .../components/add/videos-add.component.ts    | 11 ++++-
 .../list/videos-list.component.html           |  2 +-
 .../components/list/videos-list.component.ts  | 10 +++-
 .../watch/videos-watch.component.ts           |  2 -
 .../angular/videos/services/videos.service.ts | 14 +++---
 10 files changed, 122 insertions(+), 33 deletions(-)
 create mode 100644 client/angular/users/models/user.ts

diff --git a/client/angular/app/app.component.ts b/client/angular/app/app.component.ts
index 68c9ba0090..da99598363 100644
--- a/client/angular/app/app.component.ts
+++ b/client/angular/app/app.component.ts
@@ -53,11 +53,7 @@ export class AppComponent {
               private _authService: AuthService,
               private _router: Router
   ) {
-    if (localStorage.getItem('access_token')) {
-      this.isLoggedIn = true;
-    } else {
-      this.isLoggedIn = false;
-    }
+    this.isLoggedIn = this._authService.isLoggedIn();
 
     this._authService.loginChanged$.subscribe(
       status => {
diff --git a/client/angular/users/components/login/login.component.ts b/client/angular/users/components/login/login.component.ts
index 0881a3a152..35dea4f9bc 100644
--- a/client/angular/users/components/login/login.component.ts
+++ b/client/angular/users/components/login/login.component.ts
@@ -3,7 +3,7 @@ import { Router } from 'angular2/router';
 
 import { AuthService } from '../../services/auth.service';
 import { AuthStatus } from '../../models/authStatus';
-import { Token } from '../../models/token';
+import { User } from '../../models/user';
 
 @Component({
   selector: 'my-user-login',
@@ -17,16 +17,21 @@ export class UserLoginComponent {
   login(username: string, password: string) {
     this._authService.login(username, password).subscribe(
       result => {
-        if (result.error) return alert(result.error_description);
-
-        let token = new Token(result);
-        token.save();
+        const user = new User(username, result);
+        user.save();
 
         this._authService.setStatus(AuthStatus.LoggedIn);
 
         this._router.navigate(['VideosList']);
       },
-      error => alert(error)
+      error => {
+        if (error.error === 'invalid_grant') {
+          alert('Credentials are invalid.');
+        }
+        else {
+          alert(`${error.error}: ${error.error_description}`)
+        }
+      }
     );
   }
 }
diff --git a/client/angular/users/models/token.ts b/client/angular/users/models/token.ts
index 688dfdc803..906bf501b4 100644
--- a/client/angular/users/models/token.ts
+++ b/client/angular/users/models/token.ts
@@ -3,13 +3,27 @@ export class Token {
   refresh_token: string;
   token_type: string;
 
-  constructor (hash) {
-    this.access_token = hash.access_token;
-    this.refresh_token = hash.refresh_token;
-    this.token_type = hash.token_type;
+  constructor (hash?: any) {
+    if (hash) {
+      this.access_token = hash.access_token;
+      this.refresh_token = hash.refresh_token;
+      if (hash.token_type === 'bearer') {
+        this.token_type = 'Bearer';
+      } else {
+        this.token_type = hash.token_type;
+      }
+    }
   }
 
-  save() {
+  static load(): Token {
+    return new Token({
+      access_token: localStorage.getItem('access_token'),
+      refresh_token: localStorage.getItem('refresh_token'),
+      token_type: localStorage.getItem('token_type')
+    });
+  }
+
+  save():void {
     localStorage.setItem('access_token', this.access_token);
     localStorage.setItem('refresh_token', this.refresh_token);
     localStorage.setItem('token_type', this.token_type);
diff --git a/client/angular/users/models/user.ts b/client/angular/users/models/user.ts
new file mode 100644
index 0000000000..2c56a61327
--- /dev/null
+++ b/client/angular/users/models/user.ts
@@ -0,0 +1,20 @@
+import { Token } from './token';
+
+export class User {
+  username: string;
+  token: Token;
+
+  constructor (username: string, hash_token: any) {
+    this.username = username;
+    this.token = new Token(hash_token);
+  }
+
+  static load(): User {
+    return new User(localStorage.getItem('username'), Token.load());
+  }
+
+  save(): void {
+    localStorage.setItem('username', this.username);
+    this.token.save();
+  }
+}
diff --git a/client/angular/users/services/auth.service.ts b/client/angular/users/services/auth.service.ts
index 80886346ca..89412c3dff 100644
--- a/client/angular/users/services/auth.service.ts
+++ b/client/angular/users/services/auth.service.ts
@@ -1,20 +1,23 @@
 import { Injectable } from 'angular2/core';
-import { Http, Response, Headers, URLSearchParams } from 'angular2/http';
+import { Http, Response, Headers, URLSearchParams, RequestOptions } from 'angular2/http';
 import { Observable, Subject } from 'rxjs/Rx';
 
 import { AuthStatus } from '../models/authStatus';
+import { User } from '../models/user';
 
 @Injectable()
 export class AuthService {
-  loginChanged$ = this._loginChanged.asObservable();
-
-  private _loginChanged = new Subject<AuthStatus>();
+  loginChanged$;
 
+  private _loginChanged;
   private _baseLoginUrl = '/api/v1/users/token';
   private _clientId = '56f055587305d40b21904240';
   private _clientSecret = 'megustalabanana';
 
-  constructor (private http: Http) {}
+  constructor (private http: Http) {
+    this._loginChanged = new Subject<AuthStatus>();
+    this.loginChanged$ = this._loginChanged.asObservable();
+  }
 
   login(username: string, password: string) {
     let body = new URLSearchParams();
@@ -42,12 +45,46 @@ export class AuthService {
     // TODO make HTTP request
   }
 
+  getRequestHeader(): Headers {
+    return new Headers({ 'Authorization': `${this.getTokenType()} ${this.getToken()}` });
+  }
+
+  getAuthRequestOptions(): RequestOptions {
+    return new RequestOptions({ headers: this.getRequestHeader() });
+  }
+
+  getToken(): string {
+    return localStorage.getItem('access_token');
+  }
+
+  getTokenType(): string {
+    return localStorage.getItem('token_type');
+  }
+
+  getUser(): User {
+    if (this.isLoggedIn() === false) {
+      return null;
+    }
+
+    const user = User.load();
+
+    return user;
+  }
+
+  isLoggedIn(): boolean {
+    if (this.getToken()) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
   setStatus(status: AuthStatus) {
     this._loginChanged.next(status);
   }
 
   private handleError (error: Response) {
     console.error(error);
-    return Observable.throw(error.json().error || 'Server error');
+    return Observable.throw(error.json() || { error: 'Server error' });
   }
 }
diff --git a/client/angular/videos/components/add/videos-add.component.ts b/client/angular/videos/components/add/videos-add.component.ts
index 7ae11db226..bc7b4057c4 100644
--- a/client/angular/videos/components/add/videos-add.component.ts
+++ b/client/angular/videos/components/add/videos-add.component.ts
@@ -1,6 +1,9 @@
 import { Component, ElementRef, OnInit } from 'angular2/core';
 import { Router } from 'angular2/router';
 
+import { AuthService } from '../../../users/services/auth.service';
+import { User } from '../../../users/models/user';
+
 // TODO: import it with systemjs
 declare var jQuery:any;
 
@@ -11,14 +14,19 @@ declare var jQuery:any;
 })
 
 export class VideosAddComponent implements OnInit {
+  user: User;
   fileToUpload: any;
   progressBar: { value: number; max: number; } = { value: 0, max: 0 };
 
   private _form: any;
 
-  constructor(private _router: Router, private _elementRef: ElementRef) {}
+  constructor(
+    private _router: Router, private _elementRef: ElementRef,
+    private _authService: AuthService
+  ) {}
 
   ngOnInit() {
+    this.user = User.load();
     jQuery(this._elementRef.nativeElement).find('#videofile').fileupload({
       url: '/api/v1/videos',
       dataType: 'json',
@@ -49,6 +57,7 @@ export class VideosAddComponent implements OnInit {
   }
 
   uploadFile() {
+    this._form.headers = this._authService.getRequestHeader().toJSON();
     this._form.formData = jQuery(this._elementRef.nativeElement).find('form').serializeArray();
     this._form.submit();
   }
diff --git a/client/angular/videos/components/list/videos-list.component.html b/client/angular/videos/components/list/videos-list.component.html
index 38708aff61..75b860f387 100644
--- a/client/angular/videos/components/list/videos-list.component.html
+++ b/client/angular/videos/components/list/videos-list.component.html
@@ -2,7 +2,7 @@
   <div>
     <a [routerLink]="['VideosWatch', { id: video.id }]" class="video_name">{{ video.name }}</a>
     <span class="video_pod_url">{{ video.podUrl }}</span>
-    <span *ngIf="video.isLocal === true" (click)="removeVideo(video.id)" class="video_remove glyphicon glyphicon-remove"></span>
+    <span *ngIf="video.isLocal === true && user && video.author === user.username" (click)="removeVideo(video.id)" class="video_remove glyphicon glyphicon-remove"></span>
   </div>
 
   <div class="video_description">
diff --git a/client/angular/videos/components/list/videos-list.component.ts b/client/angular/videos/components/list/videos-list.component.ts
index ae58f4d7e8..b9b440d40b 100644
--- a/client/angular/videos/components/list/videos-list.component.ts
+++ b/client/angular/videos/components/list/videos-list.component.ts
@@ -1,6 +1,8 @@
 import { Component, OnInit } from 'angular2/core';
 import { ROUTER_DIRECTIVES, RouteParams } from 'angular2/router';
 
+import { AuthService } from '../../../users/services/auth.service';
+import { User } from '../../../users/models/user';
 import { VideosService } from '../../services/videos.service';
 import { Video } from '../../models/video';
 
@@ -12,11 +14,13 @@ import { Video } from '../../models/video';
 })
 
 export class VideosListComponent implements OnInit {
+  user: User = null;
   videos: Video[];
 
   private search: string;
 
   constructor(
+    private _authService: AuthService,
     private _videosService: VideosService,
     routeParams: RouteParams
   ) {
@@ -24,13 +28,17 @@ export class VideosListComponent implements OnInit {
   }
 
   ngOnInit() {
+    if (this._authService.isLoggedIn()) {
+      this.user = User.load();
+    }
+
     this.getVideos();
   }
 
   getVideos() {
     let observable = null;
 
-    if (this.search !== null) {
+    if (this.search !== null) {""
       observable = this._videosService.searchVideos(this.search);
     } else {
       observable = this._videosService.getVideos();
diff --git a/client/angular/videos/components/watch/videos-watch.component.ts b/client/angular/videos/components/watch/videos-watch.component.ts
index 28786ebb9c..d1b90c190d 100644
--- a/client/angular/videos/components/watch/videos-watch.component.ts
+++ b/client/angular/videos/components/watch/videos-watch.component.ts
@@ -1,5 +1,3 @@
-/// <reference path='../../../../typings/browser/ambient/webtorrent/webtorrent.d.ts' />
-
 import { Component, OnInit, ElementRef } from 'angular2/core';
 import { RouteParams, CanDeactivate, ComponentInstruction } from 'angular2/router';
 
diff --git a/client/angular/videos/services/videos.service.ts b/client/angular/videos/services/videos.service.ts
index 17ae89c8bf..74b6a1ddc4 100644
--- a/client/angular/videos/services/videos.service.ts
+++ b/client/angular/videos/services/videos.service.ts
@@ -1,14 +1,15 @@
-import {Injectable} from 'angular2/core';
-import {Http, Response} from 'angular2/http';
-import {Observable} from 'rxjs/Rx';
+import { Injectable } from 'angular2/core';
+import { Http, Response } from 'angular2/http';
+import { Observable } from 'rxjs/Rx';
 
-import {Video} from '../models/video';
+import { Video } from '../models/video';
+import { AuthService } from '../../users/services/auth.service';
 
 @Injectable()
 export class VideosService {
   private _baseVideoUrl = '/api/v1/videos/';
 
-  constructor (private http: Http) {}
+  constructor (private http: Http, private _authService: AuthService) {}
 
   getVideos() {
     return this.http.get(this._baseVideoUrl)
@@ -24,7 +25,8 @@ export class VideosService {
 
   removeVideo(id: string) {
     if (confirm('Are you sure?')) {
-      return this.http.delete(this._baseVideoUrl + id)
+      const options = this._authService.getAuthRequestOptions();
+      return this.http.delete(this._baseVideoUrl + id, options)
                       .map(res => <number> res.status)
                       .catch(this.handleError);
     }
-- 
GitLab