diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2016-04-14 22:07:46 +0200 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2016-04-14 22:07:46 +0200 |
commit | 1553e15d82b8a1ec4967a90d43b33274f8215c44 (patch) | |
tree | ee53fdbb32895153a1fd2470e1c51cf1d9a38e77 /client/angular | |
parent | 0c1cbbfe29d91c95f9c574b57adf067654b8b5b4 (diff) | |
download | PeerTube-1553e15d82b8a1ec4967a90d43b33274f8215c44.tar.gz PeerTube-1553e15d82b8a1ec4967a90d43b33274f8215c44.tar.zst PeerTube-1553e15d82b8a1ec4967a90d43b33274f8215c44.zip |
Implement user requests autorizations in the client side
Diffstat (limited to 'client/angular')
10 files changed, 122 insertions, 33 deletions
diff --git a/client/angular/app/app.component.ts b/client/angular/app/app.component.ts index 68c9ba009..da9959836 100644 --- a/client/angular/app/app.component.ts +++ b/client/angular/app/app.component.ts | |||
@@ -53,11 +53,7 @@ export class AppComponent { | |||
53 | private _authService: AuthService, | 53 | private _authService: AuthService, |
54 | private _router: Router | 54 | private _router: Router |
55 | ) { | 55 | ) { |
56 | if (localStorage.getItem('access_token')) { | 56 | this.isLoggedIn = this._authService.isLoggedIn(); |
57 | this.isLoggedIn = true; | ||
58 | } else { | ||
59 | this.isLoggedIn = false; | ||
60 | } | ||
61 | 57 | ||
62 | this._authService.loginChanged$.subscribe( | 58 | this._authService.loginChanged$.subscribe( |
63 | status => { | 59 | status => { |
diff --git a/client/angular/users/components/login/login.component.ts b/client/angular/users/components/login/login.component.ts index 0881a3a15..35dea4f9b 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'; | |||
3 | 3 | ||
4 | import { AuthService } from '../../services/auth.service'; | 4 | import { AuthService } from '../../services/auth.service'; |
5 | import { AuthStatus } from '../../models/authStatus'; | 5 | import { AuthStatus } from '../../models/authStatus'; |
6 | import { Token } from '../../models/token'; | 6 | import { User } from '../../models/user'; |
7 | 7 | ||
8 | @Component({ | 8 | @Component({ |
9 | selector: 'my-user-login', | 9 | selector: 'my-user-login', |
@@ -17,16 +17,21 @@ export class UserLoginComponent { | |||
17 | login(username: string, password: string) { | 17 | login(username: string, password: string) { |
18 | this._authService.login(username, password).subscribe( | 18 | this._authService.login(username, password).subscribe( |
19 | result => { | 19 | result => { |
20 | if (result.error) return alert(result.error_description); | 20 | const user = new User(username, result); |
21 | 21 | user.save(); | |
22 | let token = new Token(result); | ||
23 | token.save(); | ||
24 | 22 | ||
25 | this._authService.setStatus(AuthStatus.LoggedIn); | 23 | this._authService.setStatus(AuthStatus.LoggedIn); |
26 | 24 | ||
27 | this._router.navigate(['VideosList']); | 25 | this._router.navigate(['VideosList']); |
28 | }, | 26 | }, |
29 | error => alert(error) | 27 | error => { |
28 | if (error.error === 'invalid_grant') { | ||
29 | alert('Credentials are invalid.'); | ||
30 | } | ||
31 | else { | ||
32 | alert(`${error.error}: ${error.error_description}`) | ||
33 | } | ||
34 | } | ||
30 | ); | 35 | ); |
31 | } | 36 | } |
32 | } | 37 | } |
diff --git a/client/angular/users/models/token.ts b/client/angular/users/models/token.ts index 688dfdc80..906bf501b 100644 --- a/client/angular/users/models/token.ts +++ b/client/angular/users/models/token.ts | |||
@@ -3,13 +3,27 @@ export class Token { | |||
3 | refresh_token: string; | 3 | refresh_token: string; |
4 | token_type: string; | 4 | token_type: string; |
5 | 5 | ||
6 | constructor (hash) { | 6 | constructor (hash?: any) { |
7 | this.access_token = hash.access_token; | 7 | if (hash) { |
8 | this.refresh_token = hash.refresh_token; | 8 | this.access_token = hash.access_token; |
9 | this.token_type = hash.token_type; | 9 | this.refresh_token = hash.refresh_token; |
10 | if (hash.token_type === 'bearer') { | ||
11 | this.token_type = 'Bearer'; | ||
12 | } else { | ||
13 | this.token_type = hash.token_type; | ||
14 | } | ||
15 | } | ||
10 | } | 16 | } |
11 | 17 | ||
12 | save() { | 18 | static load(): Token { |
19 | return new Token({ | ||
20 | access_token: localStorage.getItem('access_token'), | ||
21 | refresh_token: localStorage.getItem('refresh_token'), | ||
22 | token_type: localStorage.getItem('token_type') | ||
23 | }); | ||
24 | } | ||
25 | |||
26 | save():void { | ||
13 | localStorage.setItem('access_token', this.access_token); | 27 | localStorage.setItem('access_token', this.access_token); |
14 | localStorage.setItem('refresh_token', this.refresh_token); | 28 | localStorage.setItem('refresh_token', this.refresh_token); |
15 | localStorage.setItem('token_type', this.token_type); | 29 | 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 000000000..2c56a6132 --- /dev/null +++ b/client/angular/users/models/user.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import { Token } from './token'; | ||
2 | |||
3 | export class User { | ||
4 | username: string; | ||
5 | token: Token; | ||
6 | |||
7 | constructor (username: string, hash_token: any) { | ||
8 | this.username = username; | ||
9 | this.token = new Token(hash_token); | ||
10 | } | ||
11 | |||
12 | static load(): User { | ||
13 | return new User(localStorage.getItem('username'), Token.load()); | ||
14 | } | ||
15 | |||
16 | save(): void { | ||
17 | localStorage.setItem('username', this.username); | ||
18 | this.token.save(); | ||
19 | } | ||
20 | } | ||
diff --git a/client/angular/users/services/auth.service.ts b/client/angular/users/services/auth.service.ts index 80886346c..89412c3df 100644 --- a/client/angular/users/services/auth.service.ts +++ b/client/angular/users/services/auth.service.ts | |||
@@ -1,20 +1,23 @@ | |||
1 | import { Injectable } from 'angular2/core'; | 1 | import { Injectable } from 'angular2/core'; |
2 | import { Http, Response, Headers, URLSearchParams } from 'angular2/http'; | 2 | import { Http, Response, Headers, URLSearchParams, RequestOptions } from 'angular2/http'; |
3 | import { Observable, Subject } from 'rxjs/Rx'; | 3 | import { Observable, Subject } from 'rxjs/Rx'; |
4 | 4 | ||
5 | import { AuthStatus } from '../models/authStatus'; | 5 | import { AuthStatus } from '../models/authStatus'; |
6 | import { User } from '../models/user'; | ||
6 | 7 | ||
7 | @Injectable() | 8 | @Injectable() |
8 | export class AuthService { | 9 | export class AuthService { |
9 | loginChanged$ = this._loginChanged.asObservable(); | 10 | loginChanged$; |
10 | |||
11 | private _loginChanged = new Subject<AuthStatus>(); | ||
12 | 11 | ||
12 | private _loginChanged; | ||
13 | private _baseLoginUrl = '/api/v1/users/token'; | 13 | private _baseLoginUrl = '/api/v1/users/token'; |
14 | private _clientId = '56f055587305d40b21904240'; | 14 | private _clientId = '56f055587305d40b21904240'; |
15 | private _clientSecret = 'megustalabanana'; | 15 | private _clientSecret = 'megustalabanana'; |
16 | 16 | ||
17 | constructor (private http: Http) {} | 17 | constructor (private http: Http) { |
18 | this._loginChanged = new Subject<AuthStatus>(); | ||
19 | this.loginChanged$ = this._loginChanged.asObservable(); | ||
20 | } | ||
18 | 21 | ||
19 | login(username: string, password: string) { | 22 | login(username: string, password: string) { |
20 | let body = new URLSearchParams(); | 23 | let body = new URLSearchParams(); |
@@ -42,12 +45,46 @@ export class AuthService { | |||
42 | // TODO make HTTP request | 45 | // TODO make HTTP request |
43 | } | 46 | } |
44 | 47 | ||
48 | getRequestHeader(): Headers { | ||
49 | return new Headers({ 'Authorization': `${this.getTokenType()} ${this.getToken()}` }); | ||
50 | } | ||
51 | |||
52 | getAuthRequestOptions(): RequestOptions { | ||
53 | return new RequestOptions({ headers: this.getRequestHeader() }); | ||
54 | } | ||
55 | |||
56 | getToken(): string { | ||
57 | return localStorage.getItem('access_token'); | ||
58 | } | ||
59 | |||
60 | getTokenType(): string { | ||
61 | return localStorage.getItem('token_type'); | ||
62 | } | ||
63 | |||
64 | getUser(): User { | ||
65 | if (this.isLoggedIn() === false) { | ||
66 | return null; | ||
67 | } | ||
68 | |||
69 | const user = User.load(); | ||
70 | |||
71 | return user; | ||
72 | } | ||
73 | |||
74 | isLoggedIn(): boolean { | ||
75 | if (this.getToken()) { | ||
76 | return true; | ||
77 | } else { | ||
78 | return false; | ||
79 | } | ||
80 | } | ||
81 | |||
45 | setStatus(status: AuthStatus) { | 82 | setStatus(status: AuthStatus) { |
46 | this._loginChanged.next(status); | 83 | this._loginChanged.next(status); |
47 | } | 84 | } |
48 | 85 | ||
49 | private handleError (error: Response) { | 86 | private handleError (error: Response) { |
50 | console.error(error); | 87 | console.error(error); |
51 | return Observable.throw(error.json().error || 'Server error'); | 88 | return Observable.throw(error.json() || { error: 'Server error' }); |
52 | } | 89 | } |
53 | } | 90 | } |
diff --git a/client/angular/videos/components/add/videos-add.component.ts b/client/angular/videos/components/add/videos-add.component.ts index 7ae11db22..bc7b4057c 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 @@ | |||
1 | import { Component, ElementRef, OnInit } from 'angular2/core'; | 1 | import { Component, ElementRef, OnInit } from 'angular2/core'; |
2 | import { Router } from 'angular2/router'; | 2 | import { Router } from 'angular2/router'; |
3 | 3 | ||
4 | import { AuthService } from '../../../users/services/auth.service'; | ||
5 | import { User } from '../../../users/models/user'; | ||
6 | |||
4 | // TODO: import it with systemjs | 7 | // TODO: import it with systemjs |
5 | declare var jQuery:any; | 8 | declare var jQuery:any; |
6 | 9 | ||
@@ -11,14 +14,19 @@ declare var jQuery:any; | |||
11 | }) | 14 | }) |
12 | 15 | ||
13 | export class VideosAddComponent implements OnInit { | 16 | export class VideosAddComponent implements OnInit { |
17 | user: User; | ||
14 | fileToUpload: any; | 18 | fileToUpload: any; |
15 | progressBar: { value: number; max: number; } = { value: 0, max: 0 }; | 19 | progressBar: { value: number; max: number; } = { value: 0, max: 0 }; |
16 | 20 | ||
17 | private _form: any; | 21 | private _form: any; |
18 | 22 | ||
19 | constructor(private _router: Router, private _elementRef: ElementRef) {} | 23 | constructor( |
24 | private _router: Router, private _elementRef: ElementRef, | ||
25 | private _authService: AuthService | ||
26 | ) {} | ||
20 | 27 | ||
21 | ngOnInit() { | 28 | ngOnInit() { |
29 | this.user = User.load(); | ||
22 | jQuery(this._elementRef.nativeElement).find('#videofile').fileupload({ | 30 | jQuery(this._elementRef.nativeElement).find('#videofile').fileupload({ |
23 | url: '/api/v1/videos', | 31 | url: '/api/v1/videos', |
24 | dataType: 'json', | 32 | dataType: 'json', |
@@ -49,6 +57,7 @@ export class VideosAddComponent implements OnInit { | |||
49 | } | 57 | } |
50 | 58 | ||
51 | uploadFile() { | 59 | uploadFile() { |
60 | this._form.headers = this._authService.getRequestHeader().toJSON(); | ||
52 | this._form.formData = jQuery(this._elementRef.nativeElement).find('form').serializeArray(); | 61 | this._form.formData = jQuery(this._elementRef.nativeElement).find('form').serializeArray(); |
53 | this._form.submit(); | 62 | this._form.submit(); |
54 | } | 63 | } |
diff --git a/client/angular/videos/components/list/videos-list.component.html b/client/angular/videos/components/list/videos-list.component.html index 38708aff6..75b860f38 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 @@ | |||
2 | <div> | 2 | <div> |
3 | <a [routerLink]="['VideosWatch', { id: video.id }]" class="video_name">{{ video.name }}</a> | 3 | <a [routerLink]="['VideosWatch', { id: video.id }]" class="video_name">{{ video.name }}</a> |
4 | <span class="video_pod_url">{{ video.podUrl }}</span> | 4 | <span class="video_pod_url">{{ video.podUrl }}</span> |
5 | <span *ngIf="video.isLocal === true" (click)="removeVideo(video.id)" class="video_remove glyphicon glyphicon-remove"></span> | 5 | <span *ngIf="video.isLocal === true && user && video.author === user.username" (click)="removeVideo(video.id)" class="video_remove glyphicon glyphicon-remove"></span> |
6 | </div> | 6 | </div> |
7 | 7 | ||
8 | <div class="video_description"> | 8 | <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 ae58f4d7e..b9b440d40 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 @@ | |||
1 | import { Component, OnInit } from 'angular2/core'; | 1 | import { Component, OnInit } from 'angular2/core'; |
2 | import { ROUTER_DIRECTIVES, RouteParams } from 'angular2/router'; | 2 | import { ROUTER_DIRECTIVES, RouteParams } from 'angular2/router'; |
3 | 3 | ||
4 | import { AuthService } from '../../../users/services/auth.service'; | ||
5 | import { User } from '../../../users/models/user'; | ||
4 | import { VideosService } from '../../services/videos.service'; | 6 | import { VideosService } from '../../services/videos.service'; |
5 | import { Video } from '../../models/video'; | 7 | import { Video } from '../../models/video'; |
6 | 8 | ||
@@ -12,11 +14,13 @@ import { Video } from '../../models/video'; | |||
12 | }) | 14 | }) |
13 | 15 | ||
14 | export class VideosListComponent implements OnInit { | 16 | export class VideosListComponent implements OnInit { |
17 | user: User = null; | ||
15 | videos: Video[]; | 18 | videos: Video[]; |
16 | 19 | ||
17 | private search: string; | 20 | private search: string; |
18 | 21 | ||
19 | constructor( | 22 | constructor( |
23 | private _authService: AuthService, | ||
20 | private _videosService: VideosService, | 24 | private _videosService: VideosService, |
21 | routeParams: RouteParams | 25 | routeParams: RouteParams |
22 | ) { | 26 | ) { |
@@ -24,13 +28,17 @@ export class VideosListComponent implements OnInit { | |||
24 | } | 28 | } |
25 | 29 | ||
26 | ngOnInit() { | 30 | ngOnInit() { |
31 | if (this._authService.isLoggedIn()) { | ||
32 | this.user = User.load(); | ||
33 | } | ||
34 | |||
27 | this.getVideos(); | 35 | this.getVideos(); |
28 | } | 36 | } |
29 | 37 | ||
30 | getVideos() { | 38 | getVideos() { |
31 | let observable = null; | 39 | let observable = null; |
32 | 40 | ||
33 | if (this.search !== null) { | 41 | if (this.search !== null) {"" |
34 | observable = this._videosService.searchVideos(this.search); | 42 | observable = this._videosService.searchVideos(this.search); |
35 | } else { | 43 | } else { |
36 | observable = this._videosService.getVideos(); | 44 | 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 28786ebb9..d1b90c190 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 @@ | |||
1 | /// <reference path='../../../../typings/browser/ambient/webtorrent/webtorrent.d.ts' /> | ||
2 | |||
3 | import { Component, OnInit, ElementRef } from 'angular2/core'; | 1 | import { Component, OnInit, ElementRef } from 'angular2/core'; |
4 | import { RouteParams, CanDeactivate, ComponentInstruction } from 'angular2/router'; | 2 | import { RouteParams, CanDeactivate, ComponentInstruction } from 'angular2/router'; |
5 | 3 | ||
diff --git a/client/angular/videos/services/videos.service.ts b/client/angular/videos/services/videos.service.ts index 17ae89c8b..74b6a1ddc 100644 --- a/client/angular/videos/services/videos.service.ts +++ b/client/angular/videos/services/videos.service.ts | |||
@@ -1,14 +1,15 @@ | |||
1 | import {Injectable} from 'angular2/core'; | 1 | import { Injectable } from 'angular2/core'; |
2 | import {Http, Response} from 'angular2/http'; | 2 | import { Http, Response } from 'angular2/http'; |
3 | import {Observable} from 'rxjs/Rx'; | 3 | import { Observable } from 'rxjs/Rx'; |
4 | 4 | ||
5 | import {Video} from '../models/video'; | 5 | import { Video } from '../models/video'; |
6 | import { AuthService } from '../../users/services/auth.service'; | ||
6 | 7 | ||
7 | @Injectable() | 8 | @Injectable() |
8 | export class VideosService { | 9 | export class VideosService { |
9 | private _baseVideoUrl = '/api/v1/videos/'; | 10 | private _baseVideoUrl = '/api/v1/videos/'; |
10 | 11 | ||
11 | constructor (private http: Http) {} | 12 | constructor (private http: Http, private _authService: AuthService) {} |
12 | 13 | ||
13 | getVideos() { | 14 | getVideos() { |
14 | return this.http.get(this._baseVideoUrl) | 15 | return this.http.get(this._baseVideoUrl) |
@@ -24,7 +25,8 @@ export class VideosService { | |||
24 | 25 | ||
25 | removeVideo(id: string) { | 26 | removeVideo(id: string) { |
26 | if (confirm('Are you sure?')) { | 27 | if (confirm('Are you sure?')) { |
27 | return this.http.delete(this._baseVideoUrl + id) | 28 | const options = this._authService.getAuthRequestOptions(); |
29 | return this.http.delete(this._baseVideoUrl + id, options) | ||
28 | .map(res => <number> res.status) | 30 | .map(res => <number> res.status) |
29 | .catch(this.handleError); | 31 | .catch(this.handleError); |
30 | } | 32 | } |