diff options
Diffstat (limited to 'client/src/app')
125 files changed, 1817 insertions, 1815 deletions
diff --git a/client/src/app/+admin/admin-routing.module.ts b/client/src/app/+admin/admin-routing.module.ts index d3adf3f3b..839913135 100644 --- a/client/src/app/+admin/admin-routing.module.ts +++ b/client/src/app/+admin/admin-routing.module.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router'; | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | 3 | ||
4 | import { AdminComponent } from './admin.component'; | 4 | import { AdminComponent } from './admin.component' |
5 | import { FriendsRoutes } from './friends'; | 5 | import { FriendsRoutes } from './friends' |
6 | import { RequestsRoutes } from './requests'; | 6 | import { RequestsRoutes } from './requests' |
7 | import { UsersRoutes } from './users'; | 7 | import { UsersRoutes } from './users' |
8 | import { VideoAbusesRoutes } from './video-abuses'; | 8 | import { VideoAbusesRoutes } from './video-abuses' |
9 | 9 | ||
10 | const adminRoutes: Routes = [ | 10 | const adminRoutes: Routes = [ |
11 | { | 11 | { |
@@ -23,7 +23,7 @@ const adminRoutes: Routes = [ | |||
23 | ...VideoAbusesRoutes | 23 | ...VideoAbusesRoutes |
24 | ] | 24 | ] |
25 | } | 25 | } |
26 | ]; | 26 | ] |
27 | 27 | ||
28 | @NgModule({ | 28 | @NgModule({ |
29 | imports: [ RouterModule.forChild(adminRoutes) ], | 29 | imports: [ RouterModule.forChild(adminRoutes) ], |
diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts index 64a7400e7..93ec216bf 100644 --- a/client/src/app/+admin/admin.component.ts +++ b/client/src/app/+admin/admin.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | template: '<router-outlet></router-outlet>' | 4 | template: '<router-outlet></router-outlet>' |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index db1ce2d7f..9ecce5dc3 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | 2 | ||
3 | import { AdminComponent } from './admin.component'; | 3 | import { AdminComponent } from './admin.component' |
4 | import { AdminRoutingModule } from './admin-routing.module'; | 4 | import { AdminRoutingModule } from './admin-routing.module' |
5 | import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends'; | 5 | import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends' |
6 | import { RequestsComponent, RequestStatsComponent, RequestService } from './requests'; | 6 | import { RequestsComponent, RequestStatsComponent, RequestService } from './requests' |
7 | import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users'; | 7 | import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users' |
8 | import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses'; | 8 | import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses' |
9 | import { SharedModule } from '../shared'; | 9 | import { SharedModule } from '../shared' |
10 | 10 | ||
11 | @NgModule({ | 11 | @NgModule({ |
12 | imports: [ | 12 | imports: [ |
diff --git a/client/src/app/+admin/friends/friend-add/friend-add.component.ts b/client/src/app/+admin/friends/friend-add/friend-add.component.ts index 12c46e5cd..35cf4a1f7 100644 --- a/client/src/app/+admin/friends/friend-add/friend-add.component.ts +++ b/client/src/app/+admin/friends/friend-add/friend-add.component.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { FormControl, FormGroup } from '@angular/forms'; | 2 | import { FormControl, FormGroup } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { ConfirmService } from '../../../core'; | 7 | import { ConfirmService } from '../../../core' |
8 | import { validateHost } from '../../../shared'; | 8 | import { validateHost } from '../../../shared' |
9 | import { FriendService } from '../shared'; | 9 | import { FriendService } from '../shared' |
10 | 10 | ||
11 | @Component({ | 11 | @Component({ |
12 | selector: 'my-friend-add', | 12 | selector: 'my-friend-add', |
@@ -14,107 +14,107 @@ import { FriendService } from '../shared'; | |||
14 | styleUrls: [ './friend-add.component.scss' ] | 14 | styleUrls: [ './friend-add.component.scss' ] |
15 | }) | 15 | }) |
16 | export class FriendAddComponent implements OnInit { | 16 | export class FriendAddComponent implements OnInit { |
17 | form: FormGroup; | 17 | form: FormGroup |
18 | hosts = [ ]; | 18 | hosts = [ ] |
19 | error: string = null; | 19 | error: string = null |
20 | 20 | ||
21 | constructor( | 21 | constructor ( |
22 | private router: Router, | 22 | private router: Router, |
23 | private notificationsService: NotificationsService, | 23 | private notificationsService: NotificationsService, |
24 | private confirmService: ConfirmService, | 24 | private confirmService: ConfirmService, |
25 | private friendService: FriendService | 25 | private friendService: FriendService |
26 | ) {} | 26 | ) {} |
27 | 27 | ||
28 | ngOnInit() { | 28 | ngOnInit () { |
29 | this.form = new FormGroup({}); | 29 | this.form = new FormGroup({}) |
30 | this.addField(); | 30 | this.addField() |
31 | } | 31 | } |
32 | 32 | ||
33 | addField() { | 33 | addField () { |
34 | this.form.addControl(`host-${this.hosts.length}`, new FormControl('', [ validateHost ])); | 34 | this.form.addControl(`host-${this.hosts.length}`, new FormControl('', [ validateHost ])) |
35 | this.hosts.push(''); | 35 | this.hosts.push('') |
36 | } | 36 | } |
37 | 37 | ||
38 | canMakeFriends() { | 38 | canMakeFriends () { |
39 | return window.location.protocol === 'https:'; | 39 | return window.location.protocol === 'https:' |
40 | } | 40 | } |
41 | 41 | ||
42 | customTrackBy(index: number, obj: any): any { | 42 | customTrackBy (index: number, obj: any): any { |
43 | return index; | 43 | return index |
44 | } | 44 | } |
45 | 45 | ||
46 | displayAddField(index: number) { | 46 | displayAddField (index: number) { |
47 | return index === (this.hosts.length - 1); | 47 | return index === (this.hosts.length - 1) |
48 | } | 48 | } |
49 | 49 | ||
50 | displayRemoveField(index: number) { | 50 | displayRemoveField (index: number) { |
51 | return (index !== 0 || this.hosts.length > 1) && index !== (this.hosts.length - 1); | 51 | return (index !== 0 || this.hosts.length > 1) && index !== (this.hosts.length - 1) |
52 | } | 52 | } |
53 | 53 | ||
54 | isFormValid() { | 54 | isFormValid () { |
55 | // Do not check the last input | 55 | // Do not check the last input |
56 | for (let i = 0; i < this.hosts.length - 1; i++) { | 56 | for (let i = 0; i < this.hosts.length - 1; i++) { |
57 | if (!this.form.controls[`host-${i}`].valid) return false; | 57 | if (!this.form.controls[`host-${i}`].valid) return false |
58 | } | 58 | } |
59 | 59 | ||
60 | const lastIndex = this.hosts.length - 1; | 60 | const lastIndex = this.hosts.length - 1 |
61 | // If the last input (which is not the first) is empty, it's ok | 61 | // If the last input (which is not the first) is empty, it's ok |
62 | if (this.hosts[lastIndex] === '' && lastIndex !== 0) { | 62 | if (this.hosts[lastIndex] === '' && lastIndex !== 0) { |
63 | return true; | 63 | return true |
64 | } else { | 64 | } else { |
65 | return this.form.controls[`host-${lastIndex}`].valid; | 65 | return this.form.controls[`host-${lastIndex}`].valid |
66 | } | 66 | } |
67 | } | 67 | } |
68 | 68 | ||
69 | removeField(index: number) { | 69 | removeField (index: number) { |
70 | // Remove the last control | 70 | // Remove the last control |
71 | this.form.removeControl(`host-${this.hosts.length - 1}`); | 71 | this.form.removeControl(`host-${this.hosts.length - 1}`) |
72 | this.hosts.splice(index, 1); | 72 | this.hosts.splice(index, 1) |
73 | } | 73 | } |
74 | 74 | ||
75 | makeFriends() { | 75 | makeFriends () { |
76 | this.error = ''; | 76 | this.error = '' |
77 | 77 | ||
78 | const notEmptyHosts = this.getNotEmptyHosts(); | 78 | const notEmptyHosts = this.getNotEmptyHosts() |
79 | if (notEmptyHosts.length === 0) { | 79 | if (notEmptyHosts.length === 0) { |
80 | this.error = 'You need to specify at least 1 host.'; | 80 | this.error = 'You need to specify at least 1 host.' |
81 | return; | 81 | return |
82 | } | 82 | } |
83 | 83 | ||
84 | if (!this.isHostsUnique(notEmptyHosts)) { | 84 | if (!this.isHostsUnique(notEmptyHosts)) { |
85 | this.error = 'Hosts need to be unique.'; | 85 | this.error = 'Hosts need to be unique.' |
86 | return; | 86 | return |
87 | } | 87 | } |
88 | 88 | ||
89 | const confirmMessage = 'Are you sure to make friends with:<br /> - ' + notEmptyHosts.join('<br /> - '); | 89 | const confirmMessage = 'Are you sure to make friends with:<br /> - ' + notEmptyHosts.join('<br /> - ') |
90 | this.confirmService.confirm(confirmMessage, 'Make friends').subscribe( | 90 | this.confirmService.confirm(confirmMessage, 'Make friends').subscribe( |
91 | res => { | 91 | res => { |
92 | if (res === false) return; | 92 | if (res === false) return |
93 | 93 | ||
94 | this.friendService.makeFriends(notEmptyHosts).subscribe( | 94 | this.friendService.makeFriends(notEmptyHosts).subscribe( |
95 | status => { | 95 | status => { |
96 | this.notificationsService.success('Sucess', 'Make friends request sent!'); | 96 | this.notificationsService.success('Sucess', 'Make friends request sent!') |
97 | this.router.navigate([ '/admin/friends/list' ]); | 97 | this.router.navigate([ '/admin/friends/list' ]) |
98 | }, | 98 | }, |
99 | 99 | ||
100 | err => this.notificationsService.error('Error', err.text) | 100 | err => this.notificationsService.error('Error', err.text) |
101 | ); | 101 | ) |
102 | } | 102 | } |
103 | ); | 103 | ) |
104 | } | 104 | } |
105 | 105 | ||
106 | private getNotEmptyHosts() { | 106 | private getNotEmptyHosts () { |
107 | const notEmptyHosts = []; | 107 | const notEmptyHosts = [] |
108 | 108 | ||
109 | Object.keys(this.form.value).forEach((hostKey) => { | 109 | Object.keys(this.form.value).forEach((hostKey) => { |
110 | const host = this.form.value[hostKey]; | 110 | const host = this.form.value[hostKey] |
111 | if (host !== '') notEmptyHosts.push(host); | 111 | if (host !== '') notEmptyHosts.push(host) |
112 | }); | 112 | }) |
113 | 113 | ||
114 | return notEmptyHosts; | 114 | return notEmptyHosts |
115 | } | 115 | } |
116 | 116 | ||
117 | private isHostsUnique(hosts: string[]) { | 117 | private isHostsUnique (hosts: string[]) { |
118 | return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host)); | 118 | return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host)) |
119 | } | 119 | } |
120 | } | 120 | } |
diff --git a/client/src/app/+admin/friends/friend-add/index.ts b/client/src/app/+admin/friends/friend-add/index.ts index a101b3be5..978ab3d46 100644 --- a/client/src/app/+admin/friends/friend-add/index.ts +++ b/client/src/app/+admin/friends/friend-add/index.ts | |||
@@ -1 +1 @@ | |||
export * from './friend-add.component'; | export * from './friend-add.component' | ||
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.ts b/client/src/app/+admin/friends/friend-list/friend-list.component.ts index 525a9fbc3..7bf9d2c6b 100644 --- a/client/src/app/+admin/friends/friend-list/friend-list.component.ts +++ b/client/src/app/+admin/friends/friend-list/friend-list.component.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications'; | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { ServerDataSource } from 'ng2-smart-table'; | 4 | import { ServerDataSource } from 'ng2-smart-table' |
5 | 5 | ||
6 | import { ConfirmService } from '../../../core'; | 6 | import { ConfirmService } from '../../../core' |
7 | import { Utils } from '../../../shared'; | 7 | import { Utils } from '../../../shared' |
8 | import { Friend, FriendService } from '../shared'; | 8 | import { Friend, FriendService } from '../shared' |
9 | 9 | ||
10 | @Component({ | 10 | @Component({ |
11 | selector: 'my-friend-list', | 11 | selector: 'my-friend-list', |
@@ -13,7 +13,7 @@ import { Friend, FriendService } from '../shared'; | |||
13 | styleUrls: [ './friend-list.component.scss' ] | 13 | styleUrls: [ './friend-list.component.scss' ] |
14 | }) | 14 | }) |
15 | export class FriendListComponent { | 15 | export class FriendListComponent { |
16 | friendsSource = null; | 16 | friendsSource = null |
17 | tableSettings = { | 17 | tableSettings = { |
18 | attr: { | 18 | attr: { |
19 | class: 'table-hover' | 19 | class: 'table-hover' |
@@ -49,36 +49,36 @@ export class FriendListComponent { | |||
49 | valuePrepareFunction: Utils.dateToHuman | 49 | valuePrepareFunction: Utils.dateToHuman |
50 | } | 50 | } |
51 | } | 51 | } |
52 | }; | 52 | } |
53 | 53 | ||
54 | constructor( | 54 | constructor ( |
55 | private notificationsService: NotificationsService, | 55 | private notificationsService: NotificationsService, |
56 | private confirmService: ConfirmService, | 56 | private confirmService: ConfirmService, |
57 | private friendService: FriendService | 57 | private friendService: FriendService |
58 | ) { | 58 | ) { |
59 | this.friendsSource = this.friendService.getDataSource(); | 59 | this.friendsSource = this.friendService.getDataSource() |
60 | } | 60 | } |
61 | 61 | ||
62 | hasFriends() { | 62 | hasFriends () { |
63 | return this.friendsSource.count() !== 0; | 63 | return this.friendsSource.count() !== 0 |
64 | } | 64 | } |
65 | 65 | ||
66 | quitFriends() { | 66 | quitFriends () { |
67 | const confirmMessage = 'Do you really want to quit your friends? All their videos will be deleted.'; | 67 | const confirmMessage = 'Do you really want to quit your friends? All their videos will be deleted.' |
68 | this.confirmService.confirm(confirmMessage, 'Quit friends').subscribe( | 68 | this.confirmService.confirm(confirmMessage, 'Quit friends').subscribe( |
69 | res => { | 69 | res => { |
70 | if (res === false) return; | 70 | if (res === false) return |
71 | 71 | ||
72 | this.friendService.quitFriends().subscribe( | 72 | this.friendService.quitFriends().subscribe( |
73 | status => { | 73 | status => { |
74 | this.notificationsService.success('Sucess', 'Friends left!'); | 74 | this.notificationsService.success('Sucess', 'Friends left!') |
75 | 75 | ||
76 | this.friendsSource.refresh(); | 76 | this.friendsSource.refresh() |
77 | }, | 77 | }, |
78 | 78 | ||
79 | err => this.notificationsService.error('Error', err.text) | 79 | err => this.notificationsService.error('Error', err.text) |
80 | ); | 80 | ) |
81 | } | 81 | } |
82 | ); | 82 | ) |
83 | } | 83 | } |
84 | } | 84 | } |
diff --git a/client/src/app/+admin/friends/friend-list/index.ts b/client/src/app/+admin/friends/friend-list/index.ts index 354c978a4..c9cbd2800 100644 --- a/client/src/app/+admin/friends/friend-list/index.ts +++ b/client/src/app/+admin/friends/friend-list/index.ts | |||
@@ -1 +1 @@ | |||
export * from './friend-list.component'; | export * from './friend-list.component' | ||
diff --git a/client/src/app/+admin/friends/friends.component.ts b/client/src/app/+admin/friends/friends.component.ts index 5ca29111c..5ef0aaa03 100644 --- a/client/src/app/+admin/friends/friends.component.ts +++ b/client/src/app/+admin/friends/friends.component.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | template: '<router-outlet></router-outlet>' | 4 | template: '<router-outlet></router-outlet>' |
5 | }) | 5 | }) |
6 | |||
7 | export class FriendsComponent { | 6 | export class FriendsComponent { |
8 | } | 7 | } |
diff --git a/client/src/app/+admin/friends/friends.routes.ts b/client/src/app/+admin/friends/friends.routes.ts index 747066d1f..615b6f4f7 100644 --- a/client/src/app/+admin/friends/friends.routes.ts +++ b/client/src/app/+admin/friends/friends.routes.ts | |||
@@ -1,37 +1,37 @@ | |||
1 | import { Routes } from '@angular/router'; | 1 | import { Routes } from '@angular/router' |
2 | 2 | ||
3 | import { FriendsComponent } from './friends.component'; | 3 | import { FriendsComponent } from './friends.component' |
4 | import { FriendAddComponent } from './friend-add'; | 4 | import { FriendAddComponent } from './friend-add' |
5 | import { FriendListComponent } from './friend-list'; | 5 | import { FriendListComponent } from './friend-list' |
6 | 6 | ||
7 | export const FriendsRoutes: Routes = [ | 7 | export const FriendsRoutes: Routes = [ |
8 | { | 8 | { |
9 | path: 'friends', | 9 | path: 'friends', |
10 | component: FriendsComponent, | 10 | component: FriendsComponent, |
11 | children: [ | 11 | children: [ |
12 | { | 12 | { |
13 | path: '', | 13 | path: '', |
14 | redirectTo: 'list', | 14 | redirectTo: 'list', |
15 | pathMatch: 'full' | 15 | pathMatch: 'full' |
16 | }, | 16 | }, |
17 | { | 17 | { |
18 | path: 'list', | 18 | path: 'list', |
19 | component: FriendListComponent, | 19 | component: FriendListComponent, |
20 | data: { | 20 | data: { |
21 | meta: { | 21 | meta: { |
22 | title: 'Friends list' | 22 | title: 'Friends list' |
23 | } | ||
24 | } | 23 | } |
25 | }, | 24 | } |
26 | { | 25 | }, |
27 | path: 'add', | 26 | { |
28 | component: FriendAddComponent, | 27 | path: 'add', |
29 | data: { | 28 | component: FriendAddComponent, |
30 | meta: { | 29 | data: { |
31 | title: 'Add friends' | 30 | meta: { |
32 | } | 31 | title: 'Add friends' |
33 | } | 32 | } |
34 | } | 33 | } |
35 | ] | 34 | } |
36 | } | 35 | ] |
37 | ]; | 36 | } |
37 | ] | ||
diff --git a/client/src/app/+admin/friends/index.ts b/client/src/app/+admin/friends/index.ts index dd4df2538..356dee8e9 100644 --- a/client/src/app/+admin/friends/index.ts +++ b/client/src/app/+admin/friends/index.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export * from './friend-add'; | 1 | export * from './friend-add' |
2 | export * from './friend-list'; | 2 | export * from './friend-list' |
3 | export * from './shared'; | 3 | export * from './shared' |
4 | export * from './friends.component'; | 4 | export * from './friends.component' |
5 | export * from './friends.routes'; | 5 | export * from './friends.routes' |
diff --git a/client/src/app/+admin/friends/shared/friend.model.ts b/client/src/app/+admin/friends/shared/friend.model.ts index f72156d05..6950405b9 100644 --- a/client/src/app/+admin/friends/shared/friend.model.ts +++ b/client/src/app/+admin/friends/shared/friend.model.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | export interface Friend { | 1 | export interface Friend { |
2 | id: string; | 2 | id: string |
3 | host: string; | 3 | host: string |
4 | score: number; | 4 | score: number |
5 | email: string; | 5 | email: string |
6 | createdAt: Date; | 6 | createdAt: Date |
7 | } | 7 | } |
diff --git a/client/src/app/+admin/friends/shared/friend.service.ts b/client/src/app/+admin/friends/shared/friend.service.ts index 6e51c954f..f4ecd36ad 100644 --- a/client/src/app/+admin/friends/shared/friend.service.ts +++ b/client/src/app/+admin/friends/shared/friend.service.ts | |||
@@ -1,39 +1,39 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Observable } from 'rxjs/Observable'; | 2 | import { Observable } from 'rxjs/Observable' |
3 | import 'rxjs/add/operator/catch'; | 3 | import 'rxjs/add/operator/catch' |
4 | import 'rxjs/add/operator/map'; | 4 | import 'rxjs/add/operator/map' |
5 | 5 | ||
6 | import { ServerDataSource } from 'ng2-smart-table'; | 6 | import { ServerDataSource } from 'ng2-smart-table' |
7 | 7 | ||
8 | import { Friend } from './friend.model'; | 8 | import { Friend } from './friend.model' |
9 | import { AuthHttp, RestExtractor, RestDataSource, ResultList } from '../../../shared'; | 9 | import { AuthHttp, RestExtractor, RestDataSource, ResultList } from '../../../shared' |
10 | 10 | ||
11 | @Injectable() | 11 | @Injectable() |
12 | export class FriendService { | 12 | export class FriendService { |
13 | private static BASE_FRIEND_URL = API_URL + '/api/v1/pods/'; | 13 | private static BASE_FRIEND_URL = API_URL + '/api/v1/pods/' |
14 | 14 | ||
15 | constructor ( | 15 | constructor ( |
16 | private authHttp: AuthHttp, | 16 | private authHttp: AuthHttp, |
17 | private restExtractor: RestExtractor | 17 | private restExtractor: RestExtractor |
18 | ) {} | 18 | ) {} |
19 | 19 | ||
20 | getDataSource() { | 20 | getDataSource () { |
21 | return new RestDataSource(this.authHttp, FriendService.BASE_FRIEND_URL); | 21 | return new RestDataSource(this.authHttp, FriendService.BASE_FRIEND_URL) |
22 | } | 22 | } |
23 | 23 | ||
24 | makeFriends(notEmptyHosts) { | 24 | makeFriends (notEmptyHosts) { |
25 | const body = { | 25 | const body = { |
26 | hosts: notEmptyHosts | 26 | hosts: notEmptyHosts |
27 | }; | 27 | } |
28 | 28 | ||
29 | return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'makefriends', body) | 29 | return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'makefriends', body) |
30 | .map(this.restExtractor.extractDataBool) | 30 | .map(this.restExtractor.extractDataBool) |
31 | .catch((res) => this.restExtractor.handleError(res)); | 31 | .catch((res) => this.restExtractor.handleError(res)) |
32 | } | 32 | } |
33 | 33 | ||
34 | quitFriends() { | 34 | quitFriends () { |
35 | return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quitfriends') | 35 | return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quitfriends') |
36 | .map(res => res.status) | 36 | .map(res => res.status) |
37 | .catch((res) => this.restExtractor.handleError(res)); | 37 | .catch((res) => this.restExtractor.handleError(res)) |
38 | } | 38 | } |
39 | } | 39 | } |
diff --git a/client/src/app/+admin/friends/shared/index.ts b/client/src/app/+admin/friends/shared/index.ts index 0d671637d..41aa6edd6 100644 --- a/client/src/app/+admin/friends/shared/index.ts +++ b/client/src/app/+admin/friends/shared/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './friend.model'; | 1 | export * from './friend.model' |
2 | export * from './friend.service'; | 2 | export * from './friend.service' |
diff --git a/client/src/app/+admin/index.ts b/client/src/app/+admin/index.ts index 2f47a3cc3..11e2587c0 100644 --- a/client/src/app/+admin/index.ts +++ b/client/src/app/+admin/index.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | export * from './friends'; | 1 | export * from './friends' |
2 | export * from './requests'; | 2 | export * from './requests' |
3 | export * from './users'; | 3 | export * from './users' |
4 | export * from './admin-routing.module'; | 4 | export * from './admin-routing.module' |
5 | export * from './admin.module'; | 5 | export * from './admin.module' |
6 | export * from './admin.component'; | 6 | export * from './admin.component' |
diff --git a/client/src/app/+admin/requests/index.ts b/client/src/app/+admin/requests/index.ts index 236a9ee8f..d96a893c3 100644 --- a/client/src/app/+admin/requests/index.ts +++ b/client/src/app/+admin/requests/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './request-stats'; | 1 | export * from './request-stats' |
2 | export * from './shared'; | 2 | export * from './shared' |
3 | export * from './requests.component'; | 3 | export * from './requests.component' |
4 | export * from './requests.routes'; | 4 | export * from './requests.routes' |
diff --git a/client/src/app/+admin/requests/request-stats/index.ts b/client/src/app/+admin/requests/request-stats/index.ts index be3a66f77..740c401bb 100644 --- a/client/src/app/+admin/requests/request-stats/index.ts +++ b/client/src/app/+admin/requests/request-stats/index.ts | |||
@@ -1 +1 @@ | |||
export * from './request-stats.component'; | export * from './request-stats.component' | ||
diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.ts b/client/src/app/+admin/requests/request-stats/request-stats.component.ts index 85dd7e492..cca4926cf 100644 --- a/client/src/app/+admin/requests/request-stats/request-stats.component.ts +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { Component, OnInit, OnDestroy } from '@angular/core'; | 1 | import { Component, OnInit, OnDestroy } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications'; | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | 4 | ||
5 | import { RequestService, RequestStats } from '../shared'; | 5 | import { RequestService, RequestStats } from '../shared' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-request-stats', | 8 | selector: 'my-request-stats', |
9 | templateUrl: './request-stats.component.html', | 9 | templateUrl: './request-stats.component.html', |
10 | styleUrls: [ './request-stats.component.scss' ] | 10 | styleUrls: [ './request-stats.component.scss' ] |
11 | }) | 11 | }) |
12 | export class RequestStatsComponent implements OnInit, OnDestroy { | 12 | export class RequestStatsComponent implements OnInit, OnDestroy { |
@@ -14,70 +14,67 @@ export class RequestStatsComponent implements OnInit, OnDestroy { | |||
14 | requestScheduler: 'Basic request scheduler', | 14 | requestScheduler: 'Basic request scheduler', |
15 | requestVideoEventScheduler: 'Video events request scheduler', | 15 | requestVideoEventScheduler: 'Video events request scheduler', |
16 | requestVideoQaduScheduler: 'Quick and dirty video updates request scheduler' | 16 | requestVideoQaduScheduler: 'Quick and dirty video updates request scheduler' |
17 | }; | 17 | } |
18 | 18 | ||
19 | stats: { [ id: string ]: RequestStats } = { | 19 | stats: { [ id: string ]: RequestStats } = { |
20 | requestScheduler: null, | 20 | requestScheduler: null, |
21 | requestVideoEventScheduler: null, | 21 | requestVideoEventScheduler: null, |
22 | requestVideoQaduScheduler: null | 22 | requestVideoQaduScheduler: null |
23 | }; | 23 | } |
24 | 24 | ||
25 | private intervals: { [ id: string ]: number } = { | 25 | private intervals: { [ id: string ]: number } = { |
26 | requestScheduler: null, | 26 | requestScheduler: null, |
27 | requestVideoEventScheduler: null, | 27 | requestVideoEventScheduler: null, |
28 | requestVideoQaduScheduler: null | 28 | requestVideoQaduScheduler: null |
29 | }; | 29 | } |
30 | 30 | ||
31 | private timeouts: { [ id: string ]: number } = { | 31 | private timeouts: { [ id: string ]: number } = { |
32 | requestScheduler: null, | 32 | requestScheduler: null, |
33 | requestVideoEventScheduler: null, | 33 | requestVideoEventScheduler: null, |
34 | requestVideoQaduScheduler: null | 34 | requestVideoQaduScheduler: null |
35 | }; | 35 | } |
36 | |||
37 | 36 | ||
38 | constructor( | 37 | constructor ( |
39 | private notificationsService: NotificationsService, | 38 | private notificationsService: NotificationsService, |
40 | private requestService: RequestService | 39 | private requestService: RequestService |
41 | ) { } | 40 | ) { } |
42 | 41 | ||
43 | ngOnInit() { | 42 | ngOnInit () { |
44 | this.getStats(); | 43 | this.getStats() |
45 | this.runIntervals(); | 44 | this.runIntervals() |
46 | } | 45 | } |
47 | 46 | ||
48 | ngOnDestroy() { | 47 | ngOnDestroy () { |
49 | Object.keys(this.stats).forEach(requestSchedulerName => { | 48 | Object.keys(this.stats).forEach(requestSchedulerName => { |
50 | if (this.intervals[requestSchedulerName] !== null) { | 49 | if (this.intervals[requestSchedulerName] !== null) { |
51 | window.clearInterval(this.intervals[requestSchedulerName]); | 50 | window.clearInterval(this.intervals[requestSchedulerName]) |
52 | } | 51 | } |
53 | 52 | ||
54 | if (this.timeouts[requestSchedulerName] !== null) { | 53 | if (this.timeouts[requestSchedulerName] !== null) { |
55 | window.clearTimeout(this.timeouts[requestSchedulerName]); | 54 | window.clearTimeout(this.timeouts[requestSchedulerName]) |
56 | } | 55 | } |
57 | }); | 56 | }) |
58 | } | 57 | } |
59 | 58 | ||
60 | getStats() { | 59 | getStats () { |
61 | this.requestService.getStats().subscribe( | 60 | this.requestService.getStats().subscribe( |
62 | stats => this.stats = stats, | 61 | stats => this.stats = stats, |
63 | 62 | ||
64 | err => this.notificationsService.error('Error', err.text) | 63 | err => this.notificationsService.error('Error', err.text) |
65 | ); | 64 | ) |
66 | } | 65 | } |
67 | 66 | ||
68 | private runIntervals() { | 67 | private runIntervals () { |
69 | Object.keys(this.intervals).forEach(requestSchedulerName => { | 68 | Object.keys(this.intervals).forEach(requestSchedulerName => { |
70 | this.intervals[requestSchedulerName] = window.setInterval(() => { | 69 | this.intervals[requestSchedulerName] = window.setInterval(() => { |
71 | const stats = this.stats[requestSchedulerName]; | 70 | const stats = this.stats[requestSchedulerName] |
72 | 71 | ||
73 | stats.remainingMilliSeconds -= 1000; | 72 | stats.remainingMilliSeconds -= 1000 |
74 | 73 | ||
75 | if (stats.remainingMilliSeconds <= 0) { | 74 | if (stats.remainingMilliSeconds <= 0) { |
76 | this.timeouts[requestSchedulerName] = window.setTimeout(() => this.getStats(), stats.remainingMilliSeconds + 100); | 75 | this.timeouts[requestSchedulerName] = window.setTimeout(() => this.getStats(), stats.remainingMilliSeconds + 100) |
77 | } | 76 | } |
78 | }, 1000); | 77 | }, 1000) |
79 | }); | 78 | }) |
80 | } | 79 | } |
81 | |||
82 | |||
83 | } | 80 | } |
diff --git a/client/src/app/+admin/requests/requests.component.ts b/client/src/app/+admin/requests/requests.component.ts index 471112b45..88a90fa4e 100644 --- a/client/src/app/+admin/requests/requests.component.ts +++ b/client/src/app/+admin/requests/requests.component.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | template: '<router-outlet></router-outlet>' | 4 | template: '<router-outlet></router-outlet>' |
5 | }) | 5 | }) |
6 | |||
7 | export class RequestsComponent { | 6 | export class RequestsComponent { |
8 | } | 7 | } |
diff --git a/client/src/app/+admin/requests/requests.routes.ts b/client/src/app/+admin/requests/requests.routes.ts index 251dd0da8..84db3fea8 100644 --- a/client/src/app/+admin/requests/requests.routes.ts +++ b/client/src/app/+admin/requests/requests.routes.ts | |||
@@ -1,27 +1,27 @@ | |||
1 | import { Routes } from '@angular/router'; | 1 | import { Routes } from '@angular/router' |
2 | 2 | ||
3 | import { RequestsComponent } from './requests.component'; | 3 | import { RequestsComponent } from './requests.component' |
4 | import { RequestStatsComponent } from './request-stats'; | 4 | import { RequestStatsComponent } from './request-stats' |
5 | 5 | ||
6 | export const RequestsRoutes: Routes = [ | 6 | export const RequestsRoutes: Routes = [ |
7 | { | 7 | { |
8 | path: 'requests', | 8 | path: 'requests', |
9 | component: RequestsComponent, | 9 | component: RequestsComponent, |
10 | children: [ | 10 | children: [ |
11 | { | 11 | { |
12 | path: '', | 12 | path: '', |
13 | redirectTo: 'stats', | 13 | redirectTo: 'stats', |
14 | pathMatch: 'full' | 14 | pathMatch: 'full' |
15 | }, | 15 | }, |
16 | { | 16 | { |
17 | path: 'stats', | 17 | path: 'stats', |
18 | component: RequestStatsComponent, | 18 | component: RequestStatsComponent, |
19 | data: { | 19 | data: { |
20 | meta: { | 20 | meta: { |
21 | title: 'Request stats' | 21 | title: 'Request stats' |
22 | } | ||
23 | } | 22 | } |
24 | } | 23 | } |
25 | ] | 24 | } |
26 | } | 25 | ] |
27 | ]; | 26 | } |
27 | ] | ||
diff --git a/client/src/app/+admin/requests/shared/index.ts b/client/src/app/+admin/requests/shared/index.ts index 32ab5767b..2442e810a 100644 --- a/client/src/app/+admin/requests/shared/index.ts +++ b/client/src/app/+admin/requests/shared/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './request-stats.model'; | 1 | export * from './request-stats.model' |
2 | export * from './request.service'; | 2 | export * from './request.service' |
diff --git a/client/src/app/+admin/requests/shared/request-stats.model.ts b/client/src/app/+admin/requests/shared/request-stats.model.ts index f658c4682..31550b5c0 100644 --- a/client/src/app/+admin/requests/shared/request-stats.model.ts +++ b/client/src/app/+admin/requests/shared/request-stats.model.ts | |||
@@ -1,35 +1,35 @@ | |||
1 | export interface Request { | 1 | export interface Request { |
2 | request: any; | 2 | request: any |
3 | to: any; | 3 | to: any |
4 | } | 4 | } |
5 | 5 | ||
6 | export class RequestStats { | 6 | export class RequestStats { |
7 | requestsLimitPods: number; | 7 | requestsLimitPods: number |
8 | requestsLimitPerPod: number; | 8 | requestsLimitPerPod: number |
9 | milliSecondsInterval: number; | 9 | milliSecondsInterval: number |
10 | remainingMilliSeconds: number; | 10 | remainingMilliSeconds: number |
11 | totalRequests: number; | 11 | totalRequests: number |
12 | 12 | ||
13 | constructor(hash: { | 13 | constructor (hash: { |
14 | requestsLimitPods: number, | 14 | requestsLimitPods: number, |
15 | requestsLimitPerPod: number, | 15 | requestsLimitPerPod: number, |
16 | milliSecondsInterval: number, | 16 | milliSecondsInterval: number, |
17 | remainingMilliSeconds: number, | 17 | remainingMilliSeconds: number, |
18 | totalRequests: number; | 18 | totalRequests: number |
19 | }) { | 19 | }) { |
20 | this.requestsLimitPods = hash.requestsLimitPods; | 20 | this.requestsLimitPods = hash.requestsLimitPods |
21 | this.requestsLimitPerPod = hash.requestsLimitPerPod; | 21 | this.requestsLimitPerPod = hash.requestsLimitPerPod |
22 | this.milliSecondsInterval = hash.milliSecondsInterval; | 22 | this.milliSecondsInterval = hash.milliSecondsInterval |
23 | this.remainingMilliSeconds = hash.remainingMilliSeconds; | 23 | this.remainingMilliSeconds = hash.remainingMilliSeconds |
24 | this.totalRequests = hash.totalRequests; | 24 | this.totalRequests = hash.totalRequests |
25 | } | 25 | } |
26 | 26 | ||
27 | get remainingSeconds() { | 27 | get remainingSeconds () { |
28 | return Math.floor(this.remainingMilliSeconds / 1000); | 28 | return Math.floor(this.remainingMilliSeconds / 1000) |
29 | } | 29 | } |
30 | 30 | ||
31 | get secondsInterval() { | 31 | get secondsInterva () { |
32 | return Math.floor(this.milliSecondsInterval / 1000); | 32 | return Math.floor(this.milliSecondsInterval / 1000) |
33 | } | 33 | } |
34 | 34 | ||
35 | } | 35 | } |
diff --git a/client/src/app/+admin/requests/shared/request.service.ts b/client/src/app/+admin/requests/shared/request.service.ts index 0872ba0b8..faa6b9383 100644 --- a/client/src/app/+admin/requests/shared/request.service.ts +++ b/client/src/app/+admin/requests/shared/request.service.ts | |||
@@ -1,34 +1,34 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Observable } from 'rxjs/Observable'; | 2 | import { Observable } from 'rxjs/Observable' |
3 | import 'rxjs/add/operator/catch'; | 3 | import 'rxjs/add/operator/catch' |
4 | import 'rxjs/add/operator/map'; | 4 | import 'rxjs/add/operator/map' |
5 | 5 | ||
6 | import { RequestStats } from './request-stats.model'; | 6 | import { RequestStats } from './request-stats.model' |
7 | import { AuthHttp, RestExtractor } from '../../../shared'; | 7 | import { AuthHttp, RestExtractor } from '../../../shared' |
8 | 8 | ||
9 | @Injectable() | 9 | @Injectable() |
10 | export class RequestService { | 10 | export class RequestService { |
11 | private static BASE_REQUEST_URL = API_URL + '/api/v1/requests/'; | 11 | private static BASE_REQUEST_URL = API_URL + '/api/v1/requests/' |
12 | 12 | ||
13 | constructor ( | 13 | constructor ( |
14 | private authHttp: AuthHttp, | 14 | private authHttp: AuthHttp, |
15 | private restExtractor: RestExtractor | 15 | private restExtractor: RestExtractor |
16 | ) {} | 16 | ) {} |
17 | 17 | ||
18 | getStats(): Observable<{ [ id: string ]: RequestStats }> { | 18 | getStats (): Observable<{ [ id: string ]: RequestStats }> { |
19 | return this.authHttp.get(RequestService.BASE_REQUEST_URL + 'stats') | 19 | return this.authHttp.get(RequestService.BASE_REQUEST_URL + 'stats') |
20 | .map(this.restExtractor.extractDataGet) | 20 | .map(this.restExtractor.extractDataGet) |
21 | .map(this.buildRequestObjects) | 21 | .map(this.buildRequestObjects) |
22 | .catch((res) => this.restExtractor.handleError(res)); | 22 | .catch((res) => this.restExtractor.handleError(res)) |
23 | } | 23 | } |
24 | 24 | ||
25 | private buildRequestObjects(data: any) { | 25 | private buildRequestObjects (data: any) { |
26 | const requestSchedulers = {}; | 26 | const requestSchedulers = {} |
27 | 27 | ||
28 | Object.keys(data).forEach(requestSchedulerName => { | 28 | Object.keys(data).forEach(requestSchedulerName => { |
29 | requestSchedulers[requestSchedulerName] = new RequestStats(data[requestSchedulerName]); | 29 | requestSchedulers[requestSchedulerName] = new RequestStats(data[requestSchedulerName]) |
30 | }); | 30 | }) |
31 | 31 | ||
32 | return requestSchedulers; | 32 | return requestSchedulers |
33 | } | 33 | } |
34 | } | 34 | } |
diff --git a/client/src/app/+admin/users/index.ts b/client/src/app/+admin/users/index.ts index e98a81f62..cef2c282c 100644 --- a/client/src/app/+admin/users/index.ts +++ b/client/src/app/+admin/users/index.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export * from './shared'; | 1 | export * from './shared' |
2 | export * from './user-add'; | 2 | export * from './user-add' |
3 | export * from './user-list'; | 3 | export * from './user-list' |
4 | export * from './users.component'; | 4 | export * from './users.component' |
5 | export * from './users.routes'; | 5 | export * from './users.routes' |
diff --git a/client/src/app/+admin/users/shared/index.ts b/client/src/app/+admin/users/shared/index.ts index e17ee5c7a..1f1302dc5 100644 --- a/client/src/app/+admin/users/shared/index.ts +++ b/client/src/app/+admin/users/shared/index.ts | |||
@@ -1 +1 @@ | |||
export * from './user.service'; | export * from './user.service' | ||
diff --git a/client/src/app/+admin/users/shared/user.service.ts b/client/src/app/+admin/users/shared/user.service.ts index 9c7176d39..d52993a29 100644 --- a/client/src/app/+admin/users/shared/user.service.ts +++ b/client/src/app/+admin/users/shared/user.service.ts | |||
@@ -1,35 +1,35 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import 'rxjs/add/operator/catch'; | 2 | import 'rxjs/add/operator/catch' |
3 | import 'rxjs/add/operator/map'; | 3 | import 'rxjs/add/operator/map' |
4 | 4 | ||
5 | import { AuthHttp, RestExtractor, RestDataSource, User } from '../../../shared'; | 5 | import { AuthHttp, RestExtractor, RestDataSource, User } from '../../../shared' |
6 | 6 | ||
7 | @Injectable() | 7 | @Injectable() |
8 | export class UserService { | 8 | export class UserService { |
9 | private static BASE_USERS_URL = API_URL + '/api/v1/users/'; | 9 | private static BASE_USERS_URL = API_URL + '/api/v1/users/' |
10 | 10 | ||
11 | constructor( | 11 | constructor ( |
12 | private authHttp: AuthHttp, | 12 | private authHttp: AuthHttp, |
13 | private restExtractor: RestExtractor | 13 | private restExtractor: RestExtractor |
14 | ) {} | 14 | ) {} |
15 | 15 | ||
16 | addUser(username: string, password: string, email: string) { | 16 | addUser (username: string, password: string, email: string) { |
17 | const body = { | 17 | const body = { |
18 | username, | 18 | username, |
19 | email, | 19 | email, |
20 | password | 20 | password |
21 | }; | 21 | } |
22 | 22 | ||
23 | return this.authHttp.post(UserService.BASE_USERS_URL, body) | 23 | return this.authHttp.post(UserService.BASE_USERS_URL, body) |
24 | .map(this.restExtractor.extractDataBool) | 24 | .map(this.restExtractor.extractDataBool) |
25 | .catch(this.restExtractor.handleError); | 25 | .catch(this.restExtractor.handleError) |
26 | } | 26 | } |
27 | 27 | ||
28 | getDataSource() { | 28 | getDataSource () { |
29 | return new RestDataSource(this.authHttp, UserService.BASE_USERS_URL); | 29 | return new RestDataSource(this.authHttp, UserService.BASE_USERS_URL) |
30 | } | 30 | } |
31 | 31 | ||
32 | removeUser(user: User) { | 32 | removeUser (user: User) { |
33 | return this.authHttp.delete(UserService.BASE_USERS_URL + user.id); | 33 | return this.authHttp.delete(UserService.BASE_USERS_URL + user.id) |
34 | } | 34 | } |
35 | } | 35 | } |
diff --git a/client/src/app/+admin/users/user-add/index.ts b/client/src/app/+admin/users/user-add/index.ts index 66d5ca04f..3a4654101 100644 --- a/client/src/app/+admin/users/user-add/index.ts +++ b/client/src/app/+admin/users/user-add/index.ts | |||
@@ -1 +1 @@ | |||
export * from './user-add.component'; | export * from './user-add.component' | ||
diff --git a/client/src/app/+admin/users/user-add/user-add.component.ts b/client/src/app/+admin/users/user-add/user-add.component.ts index f1d2fde80..2d25ab469 100644 --- a/client/src/app/+admin/users/user-add/user-add.component.ts +++ b/client/src/app/+admin/users/user-add/user-add.component.ts | |||
@@ -1,71 +1,71 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { UserService } from '../shared'; | 7 | import { UserService } from '../shared' |
8 | import { | 8 | import { |
9 | FormReactive, | 9 | FormReactive, |
10 | USER_USERNAME, | 10 | USER_USERNAME, |
11 | USER_EMAIL, | 11 | USER_EMAIL, |
12 | USER_PASSWORD | 12 | USER_PASSWORD |
13 | } from '../../../shared'; | 13 | } from '../../../shared' |
14 | 14 | ||
15 | @Component({ | 15 | @Component({ |
16 | selector: 'my-user-add', | 16 | selector: 'my-user-add', |
17 | templateUrl: './user-add.component.html' | 17 | templateUrl: './user-add.component.html' |
18 | }) | 18 | }) |
19 | export class UserAddComponent extends FormReactive implements OnInit { | 19 | export class UserAddComponent extends FormReactive implements OnInit { |
20 | error: string = null; | 20 | error: string = null |
21 | 21 | ||
22 | form: FormGroup; | 22 | form: FormGroup |
23 | formErrors = { | 23 | formErrors = { |
24 | 'username': '', | 24 | 'username': '', |
25 | 'email': '', | 25 | 'email': '', |
26 | 'password': '' | 26 | 'password': '' |
27 | }; | 27 | } |
28 | validationMessages = { | 28 | validationMessages = { |
29 | 'username': USER_USERNAME.MESSAGES, | 29 | 'username': USER_USERNAME.MESSAGES, |
30 | 'email': USER_EMAIL.MESSAGES, | 30 | 'email': USER_EMAIL.MESSAGES, |
31 | 'password': USER_PASSWORD.MESSAGES, | 31 | 'password': USER_PASSWORD.MESSAGES |
32 | }; | 32 | } |
33 | 33 | ||
34 | constructor( | 34 | constructor ( |
35 | private formBuilder: FormBuilder, | 35 | private formBuilder: FormBuilder, |
36 | private router: Router, | 36 | private router: Router, |
37 | private notificationsService: NotificationsService, | 37 | private notificationsService: NotificationsService, |
38 | private userService: UserService | 38 | private userService: UserService |
39 | ) { | 39 | ) { |
40 | super(); | 40 | super() |
41 | } | 41 | } |
42 | 42 | ||
43 | buildForm() { | 43 | buildForm () { |
44 | this.form = this.formBuilder.group({ | 44 | this.form = this.formBuilder.group({ |
45 | username: [ '', USER_USERNAME.VALIDATORS ], | 45 | username: [ '', USER_USERNAME.VALIDATORS ], |
46 | email: [ '', USER_EMAIL.VALIDATORS ], | 46 | email: [ '', USER_EMAIL.VALIDATORS ], |
47 | password: [ '', USER_PASSWORD.VALIDATORS ], | 47 | password: [ '', USER_PASSWORD.VALIDATORS ] |
48 | }); | 48 | }) |
49 | 49 | ||
50 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 50 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
51 | } | 51 | } |
52 | 52 | ||
53 | ngOnInit() { | 53 | ngOnInit () { |
54 | this.buildForm(); | 54 | this.buildForm() |
55 | } | 55 | } |
56 | 56 | ||
57 | addUser() { | 57 | addUser () { |
58 | this.error = null; | 58 | this.error = null |
59 | 59 | ||
60 | const { username, password, email } = this.form.value; | 60 | const { username, password, email } = this.form.value |
61 | 61 | ||
62 | this.userService.addUser(username, password, email).subscribe( | 62 | this.userService.addUser(username, password, email).subscribe( |
63 | () => { | 63 | () => { |
64 | this.notificationsService.success('Success', `User ${username} created.`); | 64 | this.notificationsService.success('Success', `User ${username} created.`) |
65 | this.router.navigate([ '/admin/users/list' ]); | 65 | this.router.navigate([ '/admin/users/list' ]) |
66 | }, | 66 | }, |
67 | 67 | ||
68 | err => this.error = err.text | 68 | err => this.error = err.text |
69 | ); | 69 | ) |
70 | } | 70 | } |
71 | } | 71 | } |
diff --git a/client/src/app/+admin/users/user-list/index.ts b/client/src/app/+admin/users/user-list/index.ts index 51fbefa80..1826a4abe 100644 --- a/client/src/app/+admin/users/user-list/index.ts +++ b/client/src/app/+admin/users/user-list/index.ts | |||
@@ -1 +1 @@ | |||
export * from './user-list.component'; | export * from './user-list.component' | ||
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 69ae4353d..b6fb0ed99 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications'; | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | 4 | ||
5 | import { ConfirmService } from '../../../core'; | 5 | import { ConfirmService } from '../../../core' |
6 | import { User, Utils } from '../../../shared'; | 6 | import { User, Utils } from '../../../shared' |
7 | import { UserService } from '../shared'; | 7 | import { UserService } from '../shared' |
8 | 8 | ||
9 | @Component({ | 9 | @Component({ |
10 | selector: 'my-user-list', | 10 | selector: 'my-user-list', |
@@ -12,7 +12,7 @@ import { UserService } from '../shared'; | |||
12 | styleUrls: [ './user-list.component.scss' ] | 12 | styleUrls: [ './user-list.component.scss' ] |
13 | }) | 13 | }) |
14 | export class UserListComponent { | 14 | export class UserListComponent { |
15 | usersSource = null; | 15 | usersSource = null |
16 | tableSettings = { | 16 | tableSettings = { |
17 | mode: 'external', | 17 | mode: 'external', |
18 | attr: { | 18 | attr: { |
@@ -52,37 +52,37 @@ export class UserListComponent { | |||
52 | valuePrepareFunction: Utils.dateToHuman | 52 | valuePrepareFunction: Utils.dateToHuman |
53 | } | 53 | } |
54 | } | 54 | } |
55 | }; | 55 | } |
56 | 56 | ||
57 | constructor( | 57 | constructor ( |
58 | private notificationsService: NotificationsService, | 58 | private notificationsService: NotificationsService, |
59 | private confirmService: ConfirmService, | 59 | private confirmService: ConfirmService, |
60 | private userService: UserService | 60 | private userService: UserService |
61 | ) { | 61 | ) { |
62 | this.usersSource = this.userService.getDataSource(); | 62 | this.usersSource = this.userService.getDataSource() |
63 | } | 63 | } |
64 | 64 | ||
65 | removeUser({ data }) { | 65 | removeUser ({ data }) { |
66 | const user: User = data; | 66 | const user: User = data |
67 | 67 | ||
68 | if (user.username === 'root') { | 68 | if (user.username === 'root') { |
69 | this.notificationsService.error('Error', 'You cannot delete root.'); | 69 | this.notificationsService.error('Error', 'You cannot delete root.') |
70 | return; | 70 | return |
71 | } | 71 | } |
72 | 72 | ||
73 | this.confirmService.confirm('Do you really want to delete this user?', 'Delete').subscribe( | 73 | this.confirmService.confirm('Do you really want to delete this user?', 'Delete').subscribe( |
74 | res => { | 74 | res => { |
75 | if (res === false) return; | 75 | if (res === false) return |
76 | 76 | ||
77 | this.userService.removeUser(user).subscribe( | 77 | this.userService.removeUser(user).subscribe( |
78 | () => { | 78 | () => { |
79 | this.notificationsService.success('Success', `User ${user.username} deleted.`); | 79 | this.notificationsService.success('Success', `User ${user.username} deleted.`) |
80 | this.usersSource.refresh(); | 80 | this.usersSource.refresh() |
81 | }, | 81 | }, |
82 | 82 | ||
83 | err => this.notificationsService.error('Error', err.text) | 83 | err => this.notificationsService.error('Error', err.text) |
84 | ); | 84 | ) |
85 | } | 85 | } |
86 | ); | 86 | ) |
87 | } | 87 | } |
88 | } | 88 | } |
diff --git a/client/src/app/+admin/users/users.component.ts b/client/src/app/+admin/users/users.component.ts index 91af6c320..e9c8f6b0d 100644 --- a/client/src/app/+admin/users/users.component.ts +++ b/client/src/app/+admin/users/users.component.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | template: '<router-outlet></router-outlet>' | 4 | template: '<router-outlet></router-outlet>' |
5 | }) | 5 | }) |
6 | |||
7 | export class UsersComponent { | 6 | export class UsersComponent { |
8 | } | 7 | } |
diff --git a/client/src/app/+admin/users/users.routes.ts b/client/src/app/+admin/users/users.routes.ts index 21fb192e0..723c5715d 100644 --- a/client/src/app/+admin/users/users.routes.ts +++ b/client/src/app/+admin/users/users.routes.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import { Routes } from '@angular/router'; | 1 | import { Routes } from '@angular/router' |
2 | 2 | ||
3 | import { UsersComponent } from './users.component'; | 3 | import { UsersComponent } from './users.component' |
4 | import { UserAddComponent } from './user-add'; | 4 | import { UserAddComponent } from './user-add' |
5 | import { UserListComponent } from './user-list'; | 5 | import { UserListComponent } from './user-list' |
6 | 6 | ||
7 | export const UsersRoutes: Routes = [ | 7 | export const UsersRoutes: Routes = [ |
8 | { | 8 | { |
@@ -34,4 +34,4 @@ export const UsersRoutes: Routes = [ | |||
34 | } | 34 | } |
35 | ] | 35 | ] |
36 | } | 36 | } |
37 | ]; | 37 | ] |
diff --git a/client/src/app/+admin/video-abuses/index.ts b/client/src/app/+admin/video-abuses/index.ts index 7f5e65f91..395fac2e7 100644 --- a/client/src/app/+admin/video-abuses/index.ts +++ b/client/src/app/+admin/video-abuses/index.ts | |||
@@ -1,3 +1,3 @@ | |||
1 | export * from './video-abuse-list'; | 1 | export * from './video-abuse-list' |
2 | export * from './video-abuses.component'; | 2 | export * from './video-abuses.component' |
3 | export * from './video-abuses.routes'; | 3 | export * from './video-abuses.routes' |
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/index.ts b/client/src/app/+admin/video-abuses/video-abuse-list/index.ts index 3f2ed1714..01c24d860 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/index.ts +++ b/client/src/app/+admin/video-abuses/video-abuse-list/index.ts | |||
@@ -1 +1 @@ | |||
export * from './video-abuse-list.component'; | export * from './video-abuse-list.component' | ||
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts index 55d82f790..60eaebb44 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts | |||
@@ -1,15 +1,15 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications'; | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | 4 | ||
5 | import { Utils, VideoAbuseService, VideoAbuse } from '../../../shared'; | 5 | import { Utils, VideoAbuseService, VideoAbuse } from '../../../shared' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-video-abuse-list', | 8 | selector: 'my-video-abuse-list', |
9 | templateUrl: './video-abuse-list.component.html' | 9 | templateUrl: './video-abuse-list.component.html' |
10 | }) | 10 | }) |
11 | export class VideoAbuseListComponent { | 11 | export class VideoAbuseListComponent { |
12 | videoAbusesSource = null; | 12 | videoAbusesSource = null |
13 | tableSettings = { | 13 | tableSettings = { |
14 | mode: 'external', | 14 | mode: 'external', |
15 | attr: { | 15 | attr: { |
@@ -54,18 +54,18 @@ export class VideoAbuseListComponent { | |||
54 | valuePrepareFunction: Utils.dateToHuman | 54 | valuePrepareFunction: Utils.dateToHuman |
55 | } | 55 | } |
56 | } | 56 | } |
57 | }; | 57 | } |
58 | 58 | ||
59 | constructor( | 59 | constructor ( |
60 | private notificationsService: NotificationsService, | 60 | private notificationsService: NotificationsService, |
61 | private videoAbuseService: VideoAbuseService | 61 | private videoAbuseService: VideoAbuseService |
62 | ) { | 62 | ) { |
63 | this.videoAbusesSource = this.videoAbuseService.getDataSource(); | 63 | this.videoAbusesSource = this.videoAbuseService.getDataSource() |
64 | } | 64 | } |
65 | 65 | ||
66 | buildVideoLink(videoId: string) { | 66 | buildVideoLink (videoId: string) { |
67 | // TODO: transform to routerLink | 67 | // TODO: transform to routerLink |
68 | // https://github.com/akveo/ng2-smart-table/issues/57 | 68 | // https://github.com/akveo/ng2-smart-table/issues/57 |
69 | return `<a href="/videos/${videoId}" title="Go to the video">${videoId}</a>`; | 69 | return `<a href="/videos/${videoId}" title="Go to the video">${videoId}</a>` |
70 | } | 70 | } |
71 | } | 71 | } |
diff --git a/client/src/app/+admin/video-abuses/video-abuses.component.ts b/client/src/app/+admin/video-abuses/video-abuses.component.ts index 001f27e87..9dae5c0b6 100644 --- a/client/src/app/+admin/video-abuses/video-abuses.component.ts +++ b/client/src/app/+admin/video-abuses/video-abuses.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | template: '<router-outlet></router-outlet>' | 4 | template: '<router-outlet></router-outlet>' |
diff --git a/client/src/app/+admin/video-abuses/video-abuses.routes.ts b/client/src/app/+admin/video-abuses/video-abuses.routes.ts index 1f19d7885..a8c1561cd 100644 --- a/client/src/app/+admin/video-abuses/video-abuses.routes.ts +++ b/client/src/app/+admin/video-abuses/video-abuses.routes.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Routes } from '@angular/router'; | 1 | import { Routes } from '@angular/router' |
2 | 2 | ||
3 | import { VideoAbusesComponent } from './video-abuses.component'; | 3 | import { VideoAbusesComponent } from './video-abuses.component' |
4 | import { VideoAbuseListComponent } from './video-abuse-list'; | 4 | import { VideoAbuseListComponent } from './video-abuse-list' |
5 | 5 | ||
6 | export const VideoAbusesRoutes: Routes = [ | 6 | export const VideoAbusesRoutes: Routes = [ |
7 | { | 7 | { |
@@ -25,4 +25,4 @@ export const VideoAbusesRoutes: Routes = [ | |||
25 | } | 25 | } |
26 | ] | 26 | ] |
27 | } | 27 | } |
28 | ]; | 28 | ] |
diff --git a/client/src/app/account/account-change-password/account-change-password.component.ts b/client/src/app/account/account-change-password/account-change-password.component.ts index 15dc42d22..ce786cfa3 100644 --- a/client/src/app/account/account-change-password/account-change-password.component.ts +++ b/client/src/app/account/account-change-password/account-change-password.component.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { FormReactive, UserService, USER_PASSWORD } from '../../shared'; | 7 | import { FormReactive, UserService, USER_PASSWORD } from '../../shared' |
8 | 8 | ||
9 | @Component({ | 9 | @Component({ |
10 | selector: 'my-account-change-password', | 10 | selector: 'my-account-change-password', |
@@ -12,55 +12,55 @@ import { FormReactive, UserService, USER_PASSWORD } from '../../shared'; | |||
12 | }) | 12 | }) |
13 | 13 | ||
14 | export class AccountChangePasswordComponent extends FormReactive implements OnInit { | 14 | export class AccountChangePasswordComponent extends FormReactive implements OnInit { |
15 | error: string = null; | 15 | error: string = null |
16 | 16 | ||
17 | form: FormGroup; | 17 | form: FormGroup |
18 | formErrors = { | 18 | formErrors = { |
19 | 'new-password': '', | 19 | 'new-password': '', |
20 | 'new-confirmed-password': '' | 20 | 'new-confirmed-password': '' |
21 | }; | 21 | } |
22 | validationMessages = { | 22 | validationMessages = { |
23 | 'new-password': USER_PASSWORD.MESSAGES, | 23 | 'new-password': USER_PASSWORD.MESSAGES, |
24 | 'new-confirmed-password': USER_PASSWORD.MESSAGES | 24 | 'new-confirmed-password': USER_PASSWORD.MESSAGES |
25 | }; | 25 | } |
26 | 26 | ||
27 | constructor( | 27 | constructor ( |
28 | private formBuilder: FormBuilder, | 28 | private formBuilder: FormBuilder, |
29 | private router: Router, | 29 | private router: Router, |
30 | private notificationsService: NotificationsService, | 30 | private notificationsService: NotificationsService, |
31 | private userService: UserService | 31 | private userService: UserService |
32 | ) { | 32 | ) { |
33 | super(); | 33 | super() |
34 | } | 34 | } |
35 | 35 | ||
36 | buildForm() { | 36 | buildForm () { |
37 | this.form = this.formBuilder.group({ | 37 | this.form = this.formBuilder.group({ |
38 | 'new-password': [ '', USER_PASSWORD.VALIDATORS ], | 38 | 'new-password': [ '', USER_PASSWORD.VALIDATORS ], |
39 | 'new-confirmed-password': [ '', USER_PASSWORD.VALIDATORS ], | 39 | 'new-confirmed-password': [ '', USER_PASSWORD.VALIDATORS ] |
40 | }); | 40 | }) |
41 | 41 | ||
42 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 42 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
43 | } | 43 | } |
44 | 44 | ||
45 | ngOnInit() { | 45 | ngOnInit () { |
46 | this.buildForm(); | 46 | this.buildForm() |
47 | } | 47 | } |
48 | 48 | ||
49 | changePassword() { | 49 | changePassword () { |
50 | const newPassword = this.form.value['new-password']; | 50 | const newPassword = this.form.value['new-password'] |
51 | const newConfirmedPassword = this.form.value['new-confirmed-password']; | 51 | const newConfirmedPassword = this.form.value['new-confirmed-password'] |
52 | 52 | ||
53 | this.error = null; | 53 | this.error = null |
54 | 54 | ||
55 | if (newPassword !== newConfirmedPassword) { | 55 | if (newPassword !== newConfirmedPassword) { |
56 | this.error = 'The new password and the confirmed password do not correspond.'; | 56 | this.error = 'The new password and the confirmed password do not correspond.' |
57 | return; | 57 | return |
58 | } | 58 | } |
59 | 59 | ||
60 | this.userService.changePassword(newPassword).subscribe( | 60 | this.userService.changePassword(newPassword).subscribe( |
61 | () => this.notificationsService.success('Success', 'Password updated.'), | 61 | () => this.notificationsService.success('Success', 'Password updated.'), |
62 | 62 | ||
63 | err => this.error = err | 63 | err => this.error = err |
64 | ); | 64 | ) |
65 | } | 65 | } |
66 | } | 66 | } |
diff --git a/client/src/app/account/account-change-password/index.ts b/client/src/app/account/account-change-password/index.ts index 72a63e48d..44c330b66 100644 --- a/client/src/app/account/account-change-password/index.ts +++ b/client/src/app/account/account-change-password/index.ts | |||
@@ -1 +1 @@ | |||
export * from './account-change-password.component'; | export * from './account-change-password.component' | ||
diff --git a/client/src/app/account/account-details/account-details.component.ts b/client/src/app/account/account-details/account-details.component.ts index 30e5b14ee..d7531cb55 100644 --- a/client/src/app/account/account-details/account-details.component.ts +++ b/client/src/app/account/account-details/account-details.component.ts | |||
@@ -1,16 +1,16 @@ | |||
1 | import { Component, OnInit, Input } from '@angular/core'; | 1 | import { Component, OnInit, Input } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { AuthService } from '../../core'; | 7 | import { AuthService } from '../../core' |
8 | import { | 8 | import { |
9 | FormReactive, | 9 | FormReactive, |
10 | User, | 10 | User, |
11 | UserService, | 11 | UserService, |
12 | USER_PASSWORD | 12 | USER_PASSWORD |
13 | } from '../../shared'; | 13 | } from '../../shared' |
14 | 14 | ||
15 | @Component({ | 15 | @Component({ |
16 | selector: 'my-account-details', | 16 | selector: 'my-account-details', |
@@ -18,51 +18,51 @@ import { | |||
18 | }) | 18 | }) |
19 | 19 | ||
20 | export class AccountDetailsComponent extends FormReactive implements OnInit { | 20 | export class AccountDetailsComponent extends FormReactive implements OnInit { |
21 | @Input() user: User = null; | 21 | @Input() user: User = null |
22 | 22 | ||
23 | error: string = null; | 23 | error: string = null |
24 | 24 | ||
25 | form: FormGroup; | 25 | form: FormGroup |
26 | formErrors = {}; | 26 | formErrors = {} |
27 | validationMessages = {}; | 27 | validationMessages = {} |
28 | 28 | ||
29 | constructor( | 29 | constructor ( |
30 | private authService: AuthService, | 30 | private authService: AuthService, |
31 | private formBuilder: FormBuilder, | 31 | private formBuilder: FormBuilder, |
32 | private router: Router, | 32 | private router: Router, |
33 | private notificationsService: NotificationsService, | 33 | private notificationsService: NotificationsService, |
34 | private userService: UserService | 34 | private userService: UserService |
35 | ) { | 35 | ) { |
36 | super(); | 36 | super() |
37 | } | 37 | } |
38 | 38 | ||
39 | buildForm() { | 39 | buildForm () { |
40 | this.form = this.formBuilder.group({ | 40 | this.form = this.formBuilder.group({ |
41 | displayNSFW: [ this.user.displayNSFW ], | 41 | displayNSFW: [ this.user.displayNSFW ] |
42 | }); | 42 | }) |
43 | 43 | ||
44 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 44 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
45 | } | 45 | } |
46 | 46 | ||
47 | ngOnInit() { | 47 | ngOnInit () { |
48 | this.buildForm(); | 48 | this.buildForm() |
49 | } | 49 | } |
50 | 50 | ||
51 | updateDetails() { | 51 | updateDetails () { |
52 | const displayNSFW = this.form.value['displayNSFW']; | 52 | const displayNSFW = this.form.value['displayNSFW'] |
53 | const details = { | 53 | const details = { |
54 | displayNSFW | 54 | displayNSFW |
55 | }; | 55 | } |
56 | 56 | ||
57 | this.error = null; | 57 | this.error = null |
58 | this.userService.updateDetails(details).subscribe( | 58 | this.userService.updateDetails(details).subscribe( |
59 | () => { | 59 | () => { |
60 | this.notificationsService.success('Success', 'Informations updated.'); | 60 | this.notificationsService.success('Success', 'Informations updated.') |
61 | 61 | ||
62 | this.authService.refreshUserInformations(); | 62 | this.authService.refreshUserInformations() |
63 | }, | 63 | }, |
64 | 64 | ||
65 | err => this.error = err | 65 | err => this.error = err |
66 | ); | 66 | ) |
67 | } | 67 | } |
68 | } | 68 | } |
diff --git a/client/src/app/account/account-details/index.ts b/client/src/app/account/account-details/index.ts index 28f644738..4829f608a 100644 --- a/client/src/app/account/account-details/index.ts +++ b/client/src/app/account/account-details/index.ts | |||
@@ -1 +1 @@ | |||
export * from './account-details.component'; | export * from './account-details.component' | ||
diff --git a/client/src/app/account/account-routing.module.ts b/client/src/app/account/account-routing.module.ts index 9004605f3..e9b8f7031 100644 --- a/client/src/app/account/account-routing.module.ts +++ b/client/src/app/account/account-routing.module.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router'; | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | 3 | ||
4 | import { AccountComponent } from './account.component'; | 4 | import { AccountComponent } from './account.component' |
5 | 5 | ||
6 | const accountRoutes: Routes = [ | 6 | const accountRoutes: Routes = [ |
7 | { | 7 | { |
@@ -13,7 +13,7 @@ const accountRoutes: Routes = [ | |||
13 | } | 13 | } |
14 | } | 14 | } |
15 | } | 15 | } |
16 | ]; | 16 | ] |
17 | 17 | ||
18 | @NgModule({ | 18 | @NgModule({ |
19 | imports: [ RouterModule.forChild(accountRoutes) ], | 19 | imports: [ RouterModule.forChild(accountRoutes) ], |
diff --git a/client/src/app/account/account.component.ts b/client/src/app/account/account.component.ts index 57b3d4ccd..929934f67 100644 --- a/client/src/app/account/account.component.ts +++ b/client/src/app/account/account.component.ts | |||
@@ -1,16 +1,16 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { AuthService } from '../core'; | 7 | import { AuthService } from '../core' |
8 | import { | 8 | import { |
9 | FormReactive, | 9 | FormReactive, |
10 | User, | 10 | User, |
11 | UserService, | 11 | UserService, |
12 | USER_PASSWORD | 12 | USER_PASSWORD |
13 | } from '../shared'; | 13 | } from '../shared' |
14 | 14 | ||
15 | @Component({ | 15 | @Component({ |
16 | selector: 'my-account', | 16 | selector: 'my-account', |
@@ -18,11 +18,11 @@ import { | |||
18 | styleUrls: [ './account.component.scss' ] | 18 | styleUrls: [ './account.component.scss' ] |
19 | }) | 19 | }) |
20 | export class AccountComponent implements OnInit { | 20 | export class AccountComponent implements OnInit { |
21 | user: User = null; | 21 | user: User = null |
22 | 22 | ||
23 | constructor(private authService: AuthService) {} | 23 | constructor (private authService: AuthService) {} |
24 | 24 | ||
25 | ngOnInit() { | 25 | ngOnInit () { |
26 | this.user = this.authService.getUser(); | 26 | this.user = this.authService.getUser() |
27 | } | 27 | } |
28 | } | 28 | } |
diff --git a/client/src/app/account/account.module.ts b/client/src/app/account/account.module.ts index f6c141ae6..380e9d235 100644 --- a/client/src/app/account/account.module.ts +++ b/client/src/app/account/account.module.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | 2 | ||
3 | import { AccountRoutingModule } from './account-routing.module'; | 3 | import { AccountRoutingModule } from './account-routing.module' |
4 | import { AccountComponent } from './account.component'; | 4 | import { AccountComponent } from './account.component' |
5 | import { AccountChangePasswordComponent } from './account-change-password'; | 5 | import { AccountChangePasswordComponent } from './account-change-password' |
6 | import { AccountDetailsComponent } from './account-details'; | 6 | import { AccountDetailsComponent } from './account-details' |
7 | import { AccountService } from './account.service'; | 7 | import { AccountService } from './account.service' |
8 | import { SharedModule } from '../shared'; | 8 | import { SharedModule } from '../shared' |
9 | 9 | ||
10 | @NgModule({ | 10 | @NgModule({ |
11 | imports: [ | 11 | imports: [ |
diff --git a/client/src/app/account/index.ts b/client/src/app/account/index.ts index 9265fa10a..dc56ffdbd 100644 --- a/client/src/app/account/index.ts +++ b/client/src/app/account/index.ts | |||
@@ -1,3 +1,3 @@ | |||
1 | export * from './account-routing.module'; | 1 | export * from './account-routing.module' |
2 | export * from './account.component'; | 2 | export * from './account.component' |
3 | export * from './account.module'; | 3 | export * from './account.module' |
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index f9465dc9c..8036c52e6 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { Routes, RouterModule } from '@angular/router'; | 2 | import { Routes, RouterModule } from '@angular/router' |
3 | 3 | ||
4 | const routes: Routes = [ | 4 | const routes: Routes = [ |
5 | { | 5 | { |
@@ -11,11 +11,10 @@ const routes: Routes = [ | |||
11 | path: 'admin', | 11 | path: 'admin', |
12 | loadChildren: './+admin#AdminModule' | 12 | loadChildren: './+admin#AdminModule' |
13 | } | 13 | } |
14 | ]; | 14 | ] |
15 | 15 | ||
16 | @NgModule({ | 16 | @NgModule({ |
17 | imports: [ RouterModule.forRoot(routes) ], | 17 | imports: [ RouterModule.forRoot(routes) ], |
18 | exports: [ RouterModule ] | 18 | exports: [ RouterModule ] |
19 | }) | 19 | }) |
20 | export class AppRoutingModule {} | 20 | export class AppRoutingModule {} |
21 | |||
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index b8b732169..a90654e26 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component, OnInit, ViewContainerRef } from '@angular/core'; | 1 | import { Component, OnInit, ViewContainerRef } from '@angular/core' |
2 | import { Router } from '@angular/router'; | 2 | import { Router } from '@angular/router' |
3 | 3 | ||
4 | import { AuthService, ConfigService } from './core'; | 4 | import { AuthService, ConfigService } from './core' |
5 | import { VideoService } from './videos'; | 5 | import { VideoService } from './videos' |
6 | import { UserService } from './shared'; | 6 | import { UserService } from './shared' |
7 | 7 | ||
8 | @Component({ | 8 | @Component({ |
9 | selector: 'my-app', | 9 | selector: 'my-app', |
@@ -22,11 +22,11 @@ export class AppComponent implements OnInit { | |||
22 | preventDuplicates: false, | 22 | preventDuplicates: false, |
23 | preventLastDuplicates: 'visible', | 23 | preventLastDuplicates: 'visible', |
24 | rtl: false | 24 | rtl: false |
25 | }; | 25 | } |
26 | 26 | ||
27 | isMenuDisplayed = true; | 27 | isMenuDisplayed = true |
28 | 28 | ||
29 | constructor( | 29 | constructor ( |
30 | private router: Router, | 30 | private router: Router, |
31 | private authService: AuthService, | 31 | private authService: AuthService, |
32 | private configService: ConfigService, | 32 | private configService: ConfigService, |
@@ -35,46 +35,46 @@ export class AppComponent implements OnInit { | |||
35 | viewContainerRef: ViewContainerRef | 35 | viewContainerRef: ViewContainerRef |
36 | ) {} | 36 | ) {} |
37 | 37 | ||
38 | ngOnInit() { | 38 | ngOnInit () { |
39 | if (this.authService.isLoggedIn()) { | 39 | if (this.authService.isLoggedIn()) { |
40 | // The service will automatically redirect to the login page if the token is not valid anymore | 40 | // The service will automatically redirect to the login page if the token is not valid anymore |
41 | this.userService.checkTokenValidity(); | 41 | this.userService.checkTokenValidity() |
42 | } | 42 | } |
43 | 43 | ||
44 | this.configService.loadConfig(); | 44 | this.configService.loadConfig() |
45 | this.videoService.loadVideoCategories(); | 45 | this.videoService.loadVideoCategories() |
46 | this.videoService.loadVideoLicences(); | 46 | this.videoService.loadVideoLicences() |
47 | this.videoService.loadVideoLanguages(); | 47 | this.videoService.loadVideoLanguages() |
48 | 48 | ||
49 | // Do not display menu on small screens | 49 | // Do not display menu on small screens |
50 | if (window.innerWidth < 600) { | 50 | if (window.innerWidth < 600) { |
51 | this.isMenuDisplayed = false; | 51 | this.isMenuDisplayed = false |
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | isInAdmin() { | 55 | isInAdmin () { |
56 | return this.router.url.indexOf('/admin/') !== -1; | 56 | return this.router.url.indexOf('/admin/') !== -1 |
57 | } | 57 | } |
58 | 58 | ||
59 | toggleMenu() { | 59 | toggleMenu () { |
60 | this.isMenuDisplayed = !this.isMenuDisplayed; | 60 | this.isMenuDisplayed = !this.isMenuDisplayed |
61 | } | 61 | } |
62 | 62 | ||
63 | getMainColClasses() { | 63 | getMainColClasses () { |
64 | const colSizes = { | 64 | const colSizes = { |
65 | md: 10, | 65 | md: 10, |
66 | sm: 9, | 66 | sm: 9, |
67 | xs: 9 | 67 | xs: 9 |
68 | }; | 68 | } |
69 | 69 | ||
70 | // Take all width is the menu is not displayed | 70 | // Take all width is the menu is not displayed |
71 | if (this.isMenuDisplayed === false) { | 71 | if (this.isMenuDisplayed === false) { |
72 | Object.keys(colSizes).forEach(col => colSizes[col] = 12); | 72 | Object.keys(colSizes).forEach(col => colSizes[col] = 12) |
73 | } | 73 | } |
74 | 74 | ||
75 | const classes = [ 'main-col' ]; | 75 | const classes = [ 'main-col' ] |
76 | Object.keys(colSizes).forEach(col => classes.push(`col-${col}-${colSizes[col]}`)); | 76 | Object.keys(colSizes).forEach(col => classes.push(`col-${col}-${colSizes[col]}`)) |
77 | 77 | ||
78 | return classes; | 78 | return classes |
79 | } | 79 | } |
80 | } | 80 | } |
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 8a072eaac..d7c9f6548 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts | |||
@@ -1,29 +1,29 @@ | |||
1 | import { ApplicationRef, NgModule } from '@angular/core'; | 1 | import { ApplicationRef, NgModule } from '@angular/core' |
2 | import { BrowserModule } from '@angular/platform-browser'; | 2 | import { BrowserModule } from '@angular/platform-browser' |
3 | import { | 3 | import { |
4 | removeNgStyles, | 4 | removeNgStyles, |
5 | createNewHosts, | 5 | createNewHosts, |
6 | createInputTransfer | 6 | createInputTransfer |
7 | } from '@angularclass/hmr'; | 7 | } from '@angularclass/hmr' |
8 | 8 | ||
9 | import { MetaModule, MetaLoader, MetaStaticLoader, PageTitlePositioning } from '@nglibs/meta'; | 9 | import { MetaModule, MetaLoader, MetaStaticLoader, PageTitlePositioning } from '@nglibs/meta' |
10 | // TODO: remove, we need this to avoid error in ng2-smart-table | 10 | // TODO: remove, we need this to avoid error in ng2-smart-table |
11 | import 'rxjs/add/operator/toPromise'; | 11 | import 'rxjs/add/operator/toPromise' |
12 | import 'bootstrap-loader'; | 12 | import 'bootstrap-loader' |
13 | 13 | ||
14 | import { ENV_PROVIDERS } from './environment'; | 14 | import { ENV_PROVIDERS } from './environment' |
15 | import { AppRoutingModule } from './app-routing.module'; | 15 | import { AppRoutingModule } from './app-routing.module' |
16 | import { AppComponent } from './app.component'; | 16 | import { AppComponent } from './app.component' |
17 | import { AppState, InternalStateType } from './app.service'; | 17 | import { AppState, InternalStateType } from './app.service' |
18 | 18 | ||
19 | import { AccountModule } from './account'; | 19 | import { AccountModule } from './account' |
20 | import { CoreModule } from './core'; | 20 | import { CoreModule } from './core' |
21 | import { LoginModule } from './login'; | 21 | import { LoginModule } from './login' |
22 | import { SignupModule } from './signup'; | 22 | import { SignupModule } from './signup' |
23 | import { SharedModule } from './shared'; | 23 | import { SharedModule } from './shared' |
24 | import { VideosModule } from './videos'; | 24 | import { VideosModule } from './videos' |
25 | 25 | ||
26 | export function metaFactory(): MetaLoader { | 26 | export function metaFactory (): MetaLoader { |
27 | return new MetaStaticLoader({ | 27 | return new MetaStaticLoader({ |
28 | pageTitlePositioning: PageTitlePositioning.PrependPageTitle, | 28 | pageTitlePositioning: PageTitlePositioning.PrependPageTitle, |
29 | pageTitleSeparator: ' - ', | 29 | pageTitleSeparator: ' - ', |
@@ -32,19 +32,19 @@ export function metaFactory(): MetaLoader { | |||
32 | title: 'PeerTube', | 32 | title: 'PeerTube', |
33 | description: 'PeerTube, a decentralized video streaming platform using P2P (BitTorrent) directly in the web browser' | 33 | description: 'PeerTube, a decentralized video streaming platform using P2P (BitTorrent) directly in the web browser' |
34 | } | 34 | } |
35 | }); | 35 | }) |
36 | } | 36 | } |
37 | 37 | ||
38 | type StoreType = { | 38 | type StoreType = { |
39 | state: InternalStateType, | 39 | state: InternalStateType, |
40 | restoreInputValues: () => void, | 40 | restoreInputValues: () => void, |
41 | disposeOldHosts: () => void | 41 | disposeOldHosts: () => void |
42 | }; | 42 | } |
43 | 43 | ||
44 | // Application wide providers | 44 | // Application wide providers |
45 | const APP_PROVIDERS = [ | 45 | const APP_PROVIDERS = [ |
46 | AppState | 46 | AppState |
47 | ]; | 47 | ] |
48 | 48 | ||
49 | @NgModule({ | 49 | @NgModule({ |
50 | bootstrap: [ AppComponent ], | 50 | bootstrap: [ AppComponent ], |
@@ -77,59 +77,59 @@ const APP_PROVIDERS = [ | |||
77 | ] | 77 | ] |
78 | }) | 78 | }) |
79 | export class AppModule { | 79 | export class AppModule { |
80 | constructor( | 80 | constructor ( |
81 | public appRef: ApplicationRef, | 81 | public appRef: ApplicationRef, |
82 | public appState: AppState | 82 | public appState: AppState |
83 | ) {} | 83 | ) {} |
84 | 84 | ||
85 | public hmrOnInit(store: StoreType) { | 85 | public hmrOnInit (store: StoreType) { |
86 | if (!store || !store.state) { | 86 | if (!store || !store.state) { |
87 | return; | 87 | return |
88 | } | 88 | } |
89 | console.log('HMR store', JSON.stringify(store, null, 2)); | 89 | console.log('HMR store', JSON.stringify(store, null, 2)) |
90 | /** | 90 | /** |
91 | * Set state | 91 | * Set state |
92 | */ | 92 | */ |
93 | this.appState._state = store.state; | 93 | this.appState._state = store.state |
94 | /** | 94 | /** |
95 | * Set input values | 95 | * Set input values |
96 | */ | 96 | */ |
97 | if ('restoreInputValues' in store) { | 97 | if ('restoreInputValues' in store) { |
98 | let restoreInputValues = store.restoreInputValues; | 98 | let restoreInputValues = store.restoreInputValues |
99 | setTimeout(restoreInputValues); | 99 | setTimeout(restoreInputValues) |
100 | } | 100 | } |
101 | 101 | ||
102 | this.appRef.tick(); | 102 | this.appRef.tick() |
103 | delete store.state; | 103 | delete store.state |
104 | delete store.restoreInputValues; | 104 | delete store.restoreInputValues |
105 | } | 105 | } |
106 | 106 | ||
107 | public hmrOnDestroy(store: StoreType) { | 107 | public hmrOnDestroy (store: StoreType) { |
108 | const cmpLocation = this.appRef.components.map((cmp) => cmp.location.nativeElement); | 108 | const cmpLocation = this.appRef.components.map((cmp) => cmp.location.nativeElement) |
109 | /** | 109 | /** |
110 | * Save state | 110 | * Save state |
111 | */ | 111 | */ |
112 | const state = this.appState._state; | 112 | const state = this.appState._state |
113 | store.state = state; | 113 | store.state = state |
114 | /** | 114 | /** |
115 | * Recreate root elements | 115 | * Recreate root elements |
116 | */ | 116 | */ |
117 | store.disposeOldHosts = createNewHosts(cmpLocation); | 117 | store.disposeOldHosts = createNewHosts(cmpLocation) |
118 | /** | 118 | /** |
119 | * Save input values | 119 | * Save input values |
120 | */ | 120 | */ |
121 | store.restoreInputValues = createInputTransfer(); | 121 | store.restoreInputValues = createInputTransfer() |
122 | /** | 122 | /** |
123 | * Remove styles | 123 | * Remove styles |
124 | */ | 124 | */ |
125 | removeNgStyles(); | 125 | removeNgStyles() |
126 | } | 126 | } |
127 | 127 | ||
128 | public hmrAfterDestroy(store: StoreType) { | 128 | public hmrAfterDestroy (store: StoreType) { |
129 | /** | 129 | /** |
130 | * Display new elements | 130 | * Display new elements |
131 | */ | 131 | */ |
132 | store.disposeOldHosts(); | 132 | store.disposeOldHosts () |
133 | delete store.disposeOldHosts; | 133 | delete store.disposeOldHosts |
134 | } | 134 | } |
135 | } | 135 | } |
diff --git a/client/src/app/app.resolver.ts b/client/src/app/app.resolver.ts index 45774b8d1..bc054e90b 100644 --- a/client/src/app/app.resolver.ts +++ b/client/src/app/app.resolver.ts | |||
@@ -1,12 +1,14 @@ | |||
1 | import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; | 1 | /* tslint:disable */ |
2 | import { Injectable } from '@angular/core'; | 2 | |
3 | import { Observable } from 'rxjs/Observable'; | 3 | import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router' |
4 | import 'rxjs/add/observable/of'; | 4 | import { Injectable } from '@angular/core' |
5 | import { Observable } from 'rxjs/Observable' | ||
6 | import 'rxjs/add/observable/of' | ||
5 | 7 | ||
6 | @Injectable() | 8 | @Injectable() |
7 | export class DataResolver implements Resolve<any> { | 9 | export class DataResolver implements Resolve<any> { |
8 | public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { | 10 | public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { |
9 | return Observable.of({ res: 'I am data'}); | 11 | return Observable.of({ res: 'I am data'}) |
10 | } | 12 | } |
11 | } | 13 | } |
12 | 14 | ||
@@ -15,4 +17,4 @@ export class DataResolver implements Resolve<any> { | |||
15 | */ | 17 | */ |
16 | export const APP_RESOLVER_PROVIDERS = [ | 18 | export const APP_RESOLVER_PROVIDERS = [ |
17 | DataResolver | 19 | DataResolver |
18 | ]; | 20 | ] |
diff --git a/client/src/app/app.service.ts b/client/src/app/app.service.ts index a7eb880a4..abffc87f1 100644 --- a/client/src/app/app.service.ts +++ b/client/src/app/app.service.ts | |||
@@ -1,46 +1,48 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | /* tslint:disable */ |
2 | |||
3 | import { Injectable } from '@angular/core' | ||
2 | 4 | ||
3 | export type InternalStateType = { | 5 | export type InternalStateType = { |
4 | [key: string]: any | 6 | [key: string]: any |
5 | }; | 7 | } |
6 | 8 | ||
7 | @Injectable() | 9 | @Injectable() |
8 | export class AppState { | 10 | export class AppState { |
9 | 11 | ||
10 | public _state: InternalStateType = { }; | 12 | public _state: InternalStateType = { } |
11 | 13 | ||
12 | /** | 14 | /** |
13 | * Already return a clone of the current state. | 15 | * Already return a clone of the current state. |
14 | */ | 16 | */ |
15 | public get state() { | 17 | public get state() { |
16 | return this._state = this._clone(this._state); | 18 | return this._state = this._clone(this._state) |
17 | } | 19 | } |
18 | /** | 20 | /** |
19 | * Never allow mutation | 21 | * Never allow mutation |
20 | */ | 22 | */ |
21 | public set state(value) { | 23 | public set state(value) { |
22 | throw new Error('do not mutate the `.state` directly'); | 24 | throw new Error('do not mutate the `.state` directly') |
23 | } | 25 | } |
24 | 26 | ||
25 | public get(prop?: any) { | 27 | public get(prop?: any) { |
26 | /** | 28 | /** |
27 | * Use our state getter for the clone. | 29 | * Use our state getter for the clone. |
28 | */ | 30 | */ |
29 | const state = this.state; | 31 | const state = this.state |
30 | return state.hasOwnProperty(prop) ? state[prop] : state; | 32 | return state.hasOwnProperty(prop) ? state[prop] : state |
31 | } | 33 | } |
32 | 34 | ||
33 | public set(prop: string, value: any) { | 35 | public set(prop: string, value: any) { |
34 | /** | 36 | /** |
35 | * Internally mutate our state. | 37 | * Internally mutate our state. |
36 | */ | 38 | */ |
37 | return this._state[prop] = value; | 39 | return this._state[prop] = value |
38 | } | 40 | } |
39 | 41 | ||
40 | private _clone(object: InternalStateType) { | 42 | private _clone(object: InternalStateType) { |
41 | /** | 43 | /** |
42 | * Simple object clone. | 44 | * Simple object clone. |
43 | */ | 45 | */ |
44 | return JSON.parse(JSON.stringify( object )); | 46 | return JSON.parse(JSON.stringify( object )) |
45 | } | 47 | } |
46 | } | 48 | } |
diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts index 1a31a7834..65c37bcfa 100644 --- a/client/src/app/core/auth/auth-user.model.ts +++ b/client/src/app/core/auth/auth-user.model.ts | |||
@@ -1,6 +1,66 @@ | |||
1 | // Do not use the barrel (dependency loop) | 1 | // Do not use the barrel (dependency loop) |
2 | import { UserRole } from '../../../../../shared/models/user.model' | 2 | import { UserRole } from '../../../../../shared/models/user.model' |
3 | import { User } from '../../shared/users/user.model'; | 3 | import { User } from '../../shared/users/user.model' |
4 | |||
5 | export type TokenOptions = { | ||
6 | accessToken: string | ||
7 | refreshToken: string | ||
8 | tokenType: string | ||
9 | } | ||
10 | |||
11 | // Private class only used by User | ||
12 | class Tokens { | ||
13 | private static KEYS = { | ||
14 | ACCESS_TOKEN: 'access_token', | ||
15 | REFRESH_TOKEN: 'refresh_token', | ||
16 | TOKEN_TYPE: 'token_type' | ||
17 | } | ||
18 | |||
19 | accessToken: string | ||
20 | refreshToken: string | ||
21 | tokenType: string | ||
22 | |||
23 | static load () { | ||
24 | const accessTokenLocalStorage = localStorage.getItem(this.KEYS.ACCESS_TOKEN) | ||
25 | const refreshTokenLocalStorage = localStorage.getItem(this.KEYS.REFRESH_TOKEN) | ||
26 | const tokenTypeLocalStorage = localStorage.getItem(this.KEYS.TOKEN_TYPE) | ||
27 | |||
28 | if (accessTokenLocalStorage && refreshTokenLocalStorage && tokenTypeLocalStorage) { | ||
29 | return new Tokens({ | ||
30 | accessToken: accessTokenLocalStorage, | ||
31 | refreshToken: refreshTokenLocalStorage, | ||
32 | tokenType: tokenTypeLocalStorage | ||
33 | }) | ||
34 | } | ||
35 | |||
36 | return null | ||
37 | } | ||
38 | |||
39 | static flush () { | ||
40 | localStorage.removeItem(this.KEYS.ACCESS_TOKEN) | ||
41 | localStorage.removeItem(this.KEYS.REFRESH_TOKEN) | ||
42 | localStorage.removeItem(this.KEYS.TOKEN_TYPE) | ||
43 | } | ||
44 | |||
45 | constructor (hash?: TokenOptions) { | ||
46 | if (hash) { | ||
47 | this.accessToken = hash.accessToken | ||
48 | this.refreshToken = hash.refreshToken | ||
49 | |||
50 | if (hash.tokenType === 'bearer') { | ||
51 | this.tokenType = 'Bearer' | ||
52 | } else { | ||
53 | this.tokenType = hash.tokenType | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | |||
58 | save () { | ||
59 | localStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken) | ||
60 | localStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken) | ||
61 | localStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType) | ||
62 | } | ||
63 | } | ||
4 | 64 | ||
5 | export class AuthUser extends User { | 65 | export class AuthUser extends User { |
6 | private static KEYS = { | 66 | private static KEYS = { |
@@ -9,123 +69,69 @@ export class AuthUser extends User { | |||
9 | EMAIL: 'email', | 69 | EMAIL: 'email', |
10 | USERNAME: 'username', | 70 | USERNAME: 'username', |
11 | DISPLAY_NSFW: 'display_nsfw' | 71 | DISPLAY_NSFW: 'display_nsfw' |
12 | }; | 72 | } |
13 | 73 | ||
14 | tokens: Tokens; | 74 | tokens: Tokens |
15 | 75 | ||
16 | static load() { | 76 | static load () { |
17 | const usernameLocalStorage = localStorage.getItem(this.KEYS.USERNAME); | 77 | const usernameLocalStorage = localStorage.getItem(this.KEYS.USERNAME) |
18 | if (usernameLocalStorage) { | 78 | if (usernameLocalStorage) { |
19 | return new AuthUser( | 79 | return new AuthUser( |
20 | { | 80 | { |
21 | id: parseInt(localStorage.getItem(this.KEYS.ID)), | 81 | id: parseInt(localStorage.getItem(this.KEYS.ID), 10), |
22 | username: localStorage.getItem(this.KEYS.USERNAME), | 82 | username: localStorage.getItem(this.KEYS.USERNAME), |
23 | email: localStorage.getItem(this.KEYS.EMAIL), | 83 | email: localStorage.getItem(this.KEYS.EMAIL), |
24 | role: localStorage.getItem(this.KEYS.ROLE) as UserRole, | 84 | role: localStorage.getItem(this.KEYS.ROLE) as UserRole, |
25 | displayNSFW: localStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true' | 85 | displayNSFW: localStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true' |
26 | }, | 86 | }, |
27 | Tokens.load() | 87 | Tokens.load() |
28 | ); | 88 | ) |
29 | } | 89 | } |
30 | 90 | ||
31 | return null; | 91 | return null |
32 | } | 92 | } |
33 | 93 | ||
34 | static flush() { | 94 | static flush () { |
35 | localStorage.removeItem(this.KEYS.USERNAME); | 95 | localStorage.removeItem(this.KEYS.USERNAME) |
36 | localStorage.removeItem(this.KEYS.ID); | 96 | localStorage.removeItem(this.KEYS.ID) |
37 | localStorage.removeItem(this.KEYS.ROLE); | 97 | localStorage.removeItem(this.KEYS.ROLE) |
38 | localStorage.removeItem(this.KEYS.DISPLAY_NSFW); | 98 | localStorage.removeItem(this.KEYS.DISPLAY_NSFW) |
39 | Tokens.flush(); | 99 | Tokens.flush() |
40 | } | 100 | } |
41 | 101 | ||
42 | constructor(userHash: { | 102 | constructor (userHash: { |
43 | id: number, | 103 | id: number, |
44 | username: string, | 104 | username: string, |
45 | role: UserRole, | 105 | role: UserRole, |
46 | email: string, | 106 | email: string, |
47 | displayNSFW: boolean | 107 | displayNSFW: boolean |
48 | }, hashTokens: any) { | 108 | }, hashTokens: TokenOptions) { |
49 | super(userHash); | 109 | super(userHash) |
50 | this.tokens = new Tokens(hashTokens); | 110 | this.tokens = new Tokens(hashTokens) |
51 | } | ||
52 | |||
53 | getAccessToken() { | ||
54 | return this.tokens.access_token; | ||
55 | } | ||
56 | |||
57 | getRefreshToken() { | ||
58 | return this.tokens.refresh_token; | ||
59 | } | ||
60 | |||
61 | getTokenType() { | ||
62 | return this.tokens.token_type; | ||
63 | } | ||
64 | |||
65 | refreshTokens(access_token: string, refresh_token: string) { | ||
66 | this.tokens.access_token = access_token; | ||
67 | this.tokens.refresh_token = refresh_token; | ||
68 | } | 111 | } |
69 | 112 | ||
70 | save() { | 113 | getAccessToken () { |
71 | localStorage.setItem(AuthUser.KEYS.ID, this.id.toString()); | 114 | return this.tokens.accessToken |
72 | localStorage.setItem(AuthUser.KEYS.USERNAME, this.username); | ||
73 | localStorage.setItem(AuthUser.KEYS.ROLE, this.role); | ||
74 | localStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW)); | ||
75 | this.tokens.save(); | ||
76 | } | 115 | } |
77 | } | ||
78 | |||
79 | // Private class only used by User | ||
80 | class Tokens { | ||
81 | private static KEYS = { | ||
82 | ACCESS_TOKEN: 'access_token', | ||
83 | REFRESH_TOKEN: 'refresh_token', | ||
84 | TOKEN_TYPE: 'token_type', | ||
85 | }; | ||
86 | |||
87 | access_token: string; | ||
88 | refresh_token: string; | ||
89 | token_type: string; | ||
90 | |||
91 | static load() { | ||
92 | const accessTokenLocalStorage = localStorage.getItem(this.KEYS.ACCESS_TOKEN); | ||
93 | const refreshTokenLocalStorage = localStorage.getItem(this.KEYS.REFRESH_TOKEN); | ||
94 | const tokenTypeLocalStorage = localStorage.getItem(this.KEYS.TOKEN_TYPE); | ||
95 | |||
96 | if (accessTokenLocalStorage && refreshTokenLocalStorage && tokenTypeLocalStorage) { | ||
97 | return new Tokens({ | ||
98 | access_token: accessTokenLocalStorage, | ||
99 | refresh_token: refreshTokenLocalStorage, | ||
100 | token_type: tokenTypeLocalStorage | ||
101 | }); | ||
102 | } | ||
103 | 116 | ||
104 | return null; | 117 | getRefreshToken () { |
118 | return this.tokens.refreshToken | ||
105 | } | 119 | } |
106 | 120 | ||
107 | static flush() { | 121 | getTokenType () { |
108 | localStorage.removeItem(this.KEYS.ACCESS_TOKEN); | 122 | return this.tokens.tokenType |
109 | localStorage.removeItem(this.KEYS.REFRESH_TOKEN); | ||
110 | localStorage.removeItem(this.KEYS.TOKEN_TYPE); | ||
111 | } | 123 | } |
112 | 124 | ||
113 | constructor(hash?: any) { | 125 | refreshTokens (accessToken: string, refreshToken: string) { |
114 | if (hash) { | 126 | this.tokens.accessToken = accessToken |
115 | this.access_token = hash.access_token; | 127 | this.tokens.refreshToken = refreshToken |
116 | this.refresh_token = hash.refresh_token; | ||
117 | |||
118 | if (hash.token_type === 'bearer') { | ||
119 | this.token_type = 'Bearer'; | ||
120 | } else { | ||
121 | this.token_type = hash.token_type; | ||
122 | } | ||
123 | } | ||
124 | } | 128 | } |
125 | 129 | ||
126 | save() { | 130 | save () { |
127 | localStorage.setItem('access_token', this.access_token); | 131 | localStorage.setItem(AuthUser.KEYS.ID, this.id.toString()) |
128 | localStorage.setItem('refresh_token', this.refresh_token); | 132 | localStorage.setItem(AuthUser.KEYS.USERNAME, this.username) |
129 | localStorage.setItem('token_type', this.token_type); | 133 | localStorage.setItem(AuthUser.KEYS.ROLE, this.role) |
134 | localStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW)) | ||
135 | this.tokens.save() | ||
130 | } | 136 | } |
131 | } | 137 | } |
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index 4c75df1ca..32f7a5503 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts | |||
@@ -1,40 +1,40 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Headers, Http, Response, URLSearchParams } from '@angular/http'; | 2 | import { Headers, Http, Response, URLSearchParams } from '@angular/http' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | import { Observable } from 'rxjs/Observable'; | 4 | import { Observable } from 'rxjs/Observable' |
5 | import { Subject } from 'rxjs/Subject'; | 5 | import { Subject } from 'rxjs/Subject' |
6 | import 'rxjs/add/operator/map'; | 6 | import 'rxjs/add/operator/map' |
7 | import 'rxjs/add/operator/mergeMap'; | 7 | import 'rxjs/add/operator/mergeMap' |
8 | import 'rxjs/add/observable/throw'; | 8 | import 'rxjs/add/observable/throw' |
9 | 9 | ||
10 | import { NotificationsService } from 'angular2-notifications'; | 10 | import { NotificationsService } from 'angular2-notifications' |
11 | 11 | ||
12 | import { AuthStatus } from './auth-status.model'; | 12 | import { AuthStatus } from './auth-status.model' |
13 | import { AuthUser } from './auth-user.model'; | 13 | import { AuthUser } from './auth-user.model' |
14 | // Do not use the barrel (dependency loop) | 14 | // Do not use the barrel (dependency loop) |
15 | import { RestExtractor } from '../../shared/rest'; | 15 | import { RestExtractor } from '../../shared/rest' |
16 | 16 | ||
17 | @Injectable() | 17 | @Injectable() |
18 | export class AuthService { | 18 | export class AuthService { |
19 | private static BASE_CLIENT_URL = API_URL + '/api/v1/clients/local'; | 19 | private static BASE_CLIENT_URL = API_URL + '/api/v1/clients/local' |
20 | private static BASE_TOKEN_URL = API_URL + '/api/v1/users/token'; | 20 | private static BASE_TOKEN_URL = API_URL + '/api/v1/users/token' |
21 | private static BASE_USER_INFORMATIONS_URL = API_URL + '/api/v1/users/me'; | 21 | private static BASE_USER_INFORMATIONS_URL = API_URL + '/api/v1/users/me' |
22 | 22 | ||
23 | loginChangedSource: Observable<AuthStatus>; | 23 | loginChangedSource: Observable<AuthStatus> |
24 | 24 | ||
25 | private clientId: string; | 25 | private clientId: string |
26 | private clientSecret: string; | 26 | private clientSecret: string |
27 | private loginChanged: Subject<AuthStatus>; | 27 | private loginChanged: Subject<AuthStatus> |
28 | private user: AuthUser = null; | 28 | private user: AuthUser = null |
29 | 29 | ||
30 | constructor( | 30 | constructor ( |
31 | private http: Http, | 31 | private http: Http, |
32 | private notificationsService: NotificationsService, | 32 | private notificationsService: NotificationsService, |
33 | private restExtractor: RestExtractor, | 33 | private restExtractor: RestExtractor, |
34 | private router: Router | 34 | private router: Router |
35 | ) { | 35 | ) { |
36 | this.loginChanged = new Subject<AuthStatus>(); | 36 | this.loginChanged = new Subject<AuthStatus>() |
37 | this.loginChangedSource = this.loginChanged.asObservable(); | 37 | this.loginChangedSource = this.loginChanged.asObservable() |
38 | 38 | ||
39 | // Fetch the client_id/client_secret | 39 | // Fetch the client_id/client_secret |
40 | // FIXME: save in local storage? | 40 | // FIXME: save in local storage? |
@@ -43,120 +43,120 @@ export class AuthService { | |||
43 | .catch((res) => this.restExtractor.handleError(res)) | 43 | .catch((res) => this.restExtractor.handleError(res)) |
44 | .subscribe( | 44 | .subscribe( |
45 | result => { | 45 | result => { |
46 | this.clientId = result.client_id; | 46 | this.clientId = result.client_id |
47 | this.clientSecret = result.client_secret; | 47 | this.clientSecret = result.client_secret |
48 | console.log('Client credentials loaded.'); | 48 | console.log('Client credentials loaded.') |
49 | }, | 49 | }, |
50 | 50 | ||
51 | error => { | 51 | error => { |
52 | let errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`; | 52 | let errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n` |
53 | errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'; | 53 | errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.' |
54 | 54 | ||
55 | // We put a bigger timeout | 55 | // We put a bigger timeout |
56 | // This is an important message | 56 | // This is an important message |
57 | this.notificationsService.error('Error', errorMessage, { timeOut: 7000 }); | 57 | this.notificationsService.error('Error', errorMessage, { timeOut: 7000 }) |
58 | } | 58 | } |
59 | ); | 59 | ) |
60 | 60 | ||
61 | // Return null if there is nothing to load | 61 | // Return null if there is nothing to load |
62 | this.user = AuthUser.load(); | 62 | this.user = AuthUser.load() |
63 | } | 63 | } |
64 | 64 | ||
65 | getRefreshToken() { | 65 | getRefreshToken () { |
66 | if (this.user === null) return null; | 66 | if (this.user === null) return null |
67 | 67 | ||
68 | return this.user.getRefreshToken(); | 68 | return this.user.getRefreshToken() |
69 | } | 69 | } |
70 | 70 | ||
71 | getRequestHeaderValue() { | 71 | getRequestHeaderValue () { |
72 | return `${this.getTokenType()} ${this.getAccessToken()}`; | 72 | return `${this.getTokenType()} ${this.getAccessToken()}` |
73 | } | 73 | } |
74 | 74 | ||
75 | getAccessToken() { | 75 | getAccessToken () { |
76 | if (this.user === null) return null; | 76 | if (this.user === null) return null |
77 | 77 | ||
78 | return this.user.getAccessToken(); | 78 | return this.user.getAccessToken() |
79 | } | 79 | } |
80 | 80 | ||
81 | getTokenType() { | 81 | getTokenType () { |
82 | if (this.user === null) return null; | 82 | if (this.user === null) return null |
83 | 83 | ||
84 | return this.user.getTokenType(); | 84 | return this.user.getTokenType() |
85 | } | 85 | } |
86 | 86 | ||
87 | getUser(): AuthUser { | 87 | getUser () { |
88 | return this.user; | 88 | return this.user |
89 | } | 89 | } |
90 | 90 | ||
91 | isAdmin() { | 91 | isAdmin () { |
92 | if (this.user === null) return false; | 92 | if (this.user === null) return false |
93 | 93 | ||
94 | return this.user.isAdmin(); | 94 | return this.user.isAdmin() |
95 | } | 95 | } |
96 | 96 | ||
97 | isLoggedIn() { | 97 | isLoggedIn () { |
98 | if (this.getAccessToken()) { | 98 | if (this.getAccessToken()) { |
99 | return true; | 99 | return true |
100 | } else { | 100 | } else { |
101 | return false; | 101 | return false |
102 | } | 102 | } |
103 | } | 103 | } |
104 | 104 | ||
105 | login(username: string, password: string) { | 105 | login (username: string, password: string) { |
106 | let body = new URLSearchParams(); | 106 | let body = new URLSearchParams() |
107 | body.set('client_id', this.clientId); | 107 | body.set('client_id', this.clientId) |
108 | body.set('client_secret', this.clientSecret); | 108 | body.set('client_secret', this.clientSecret) |
109 | body.set('response_type', 'code'); | 109 | body.set('response_type', 'code') |
110 | body.set('grant_type', 'password'); | 110 | body.set('grant_type', 'password') |
111 | body.set('scope', 'upload'); | 111 | body.set('scope', 'upload') |
112 | body.set('username', username); | 112 | body.set('username', username) |
113 | body.set('password', password); | 113 | body.set('password', password) |
114 | 114 | ||
115 | let headers = new Headers(); | 115 | let headers = new Headers() |
116 | headers.append('Content-Type', 'application/x-www-form-urlencoded'); | 116 | headers.append('Content-Type', 'application/x-www-form-urlencoded') |
117 | 117 | ||
118 | let options = { | 118 | let options = { |
119 | headers: headers | 119 | headers: headers |
120 | }; | 120 | } |
121 | 121 | ||
122 | return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) | 122 | return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) |
123 | .map(this.restExtractor.extractDataGet) | 123 | .map(this.restExtractor.extractDataGet) |
124 | .map(res => { | 124 | .map(res => { |
125 | res.username = username; | 125 | res.username = username |
126 | return res; | 126 | return res |
127 | }) | 127 | }) |
128 | .flatMap(res => this.mergeUserInformations(res)) | 128 | .flatMap(res => this.mergeUserInformations(res)) |
129 | .map(res => this.handleLogin(res)) | 129 | .map(res => this.handleLogin(res)) |
130 | .catch((res) => this.restExtractor.handleError(res)); | 130 | .catch((res) => this.restExtractor.handleError(res)) |
131 | } | 131 | } |
132 | 132 | ||
133 | logout() { | 133 | logout () { |
134 | // TODO: make an HTTP request to revoke the tokens | 134 | // TODO: make an HTTP request to revoke the tokens |
135 | this.user = null; | 135 | this.user = null |
136 | 136 | ||
137 | AuthUser.flush(); | 137 | AuthUser.flush() |
138 | 138 | ||
139 | this.setStatus(AuthStatus.LoggedOut); | 139 | this.setStatus(AuthStatus.LoggedOut) |
140 | } | 140 | } |
141 | 141 | ||
142 | refreshAccessToken() { | 142 | refreshAccessToken () { |
143 | console.log('Refreshing token...'); | 143 | console.log('Refreshing token...') |
144 | 144 | ||
145 | const refreshToken = this.getRefreshToken(); | 145 | const refreshToken = this.getRefreshToken() |
146 | 146 | ||
147 | let body = new URLSearchParams(); | 147 | let body = new URLSearchParams() |
148 | body.set('refresh_token', refreshToken); | 148 | body.set('refresh_token', refreshToken) |
149 | body.set('client_id', this.clientId); | 149 | body.set('client_id', this.clientId) |
150 | body.set('client_secret', this.clientSecret); | 150 | body.set('client_secret', this.clientSecret) |
151 | body.set('response_type', 'code'); | 151 | body.set('response_type', 'code') |
152 | body.set('grant_type', 'refresh_token'); | 152 | body.set('grant_type', 'refresh_token') |
153 | 153 | ||
154 | let headers = new Headers(); | 154 | let headers = new Headers() |
155 | headers.append('Content-Type', 'application/x-www-form-urlencoded'); | 155 | headers.append('Content-Type', 'application/x-www-form-urlencoded') |
156 | 156 | ||
157 | let options = { | 157 | let options = { |
158 | headers: headers | 158 | headers: headers |
159 | }; | 159 | } |
160 | 160 | ||
161 | return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) | 161 | return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) |
162 | .map(this.restExtractor.extractDataGet) | 162 | .map(this.restExtractor.extractDataGet) |
@@ -164,41 +164,41 @@ export class AuthService { | |||
164 | .catch((res: Response) => { | 164 | .catch((res: Response) => { |
165 | // The refresh token is invalid? | 165 | // The refresh token is invalid? |
166 | if (res.status === 400 && res.json() && res.json().error === 'invalid_grant') { | 166 | if (res.status === 400 && res.json() && res.json().error === 'invalid_grant') { |
167 | console.error('Cannot refresh token -> logout...'); | 167 | console.error('Cannot refresh token -> logout...') |
168 | this.logout(); | 168 | this.logout() |
169 | this.router.navigate(['/login']); | 169 | this.router.navigate(['/login']) |
170 | 170 | ||
171 | return Observable.throw({ | 171 | return Observable.throw({ |
172 | json: () => '', | 172 | json: () => '', |
173 | text: () => 'You need to reconnect.' | 173 | text: () => 'You need to reconnect.' |
174 | }); | 174 | }) |
175 | } | 175 | } |
176 | 176 | ||
177 | return this.restExtractor.handleError(res); | 177 | return this.restExtractor.handleError(res) |
178 | }); | 178 | }) |
179 | } | 179 | } |
180 | 180 | ||
181 | refreshUserInformations() { | 181 | refreshUserInformations () { |
182 | const obj = { | 182 | const obj = { |
183 | access_token: this.user.getAccessToken() | 183 | access_token: this.user.getAccessToken() |
184 | }; | 184 | } |
185 | 185 | ||
186 | this.mergeUserInformations(obj) | 186 | this.mergeUserInformations (obj) |
187 | .subscribe( | 187 | .subscribe( |
188 | res => { | 188 | res => { |
189 | this.user.displayNSFW = res.displayNSFW; | 189 | this.user.displayNSFW = res.displayNSFW |
190 | this.user.role = res.role; | 190 | this.user.role = res.role |
191 | 191 | ||
192 | this.user.save(); | 192 | this.user.save() |
193 | } | 193 | } |
194 | ); | 194 | ) |
195 | } | 195 | } |
196 | 196 | ||
197 | private mergeUserInformations(obj: { access_token: string }) { | 197 | private mergeUserInformations (obj: { access_token: string }) { |
198 | // Do not call authHttp here to avoid circular dependencies headaches | 198 | // Do not call authHttp here to avoid circular dependencies headaches |
199 | 199 | ||
200 | const headers = new Headers(); | 200 | const headers = new Headers() |
201 | headers.set('Authorization', `Bearer ${obj.access_token}`); | 201 | headers.set('Authorization', `Bearer ${obj.access_token}`) |
202 | 202 | ||
203 | return this.http.get(AuthService.BASE_USER_INFORMATIONS_URL, { headers }) | 203 | return this.http.get(AuthService.BASE_USER_INFORMATIONS_URL, { headers }) |
204 | .map(res => res.json()) | 204 | .map(res => res.json()) |
@@ -207,38 +207,38 @@ export class AuthService { | |||
207 | id: res.id, | 207 | id: res.id, |
208 | role: res.role, | 208 | role: res.role, |
209 | displayNSFW: res.displayNSFW | 209 | displayNSFW: res.displayNSFW |
210 | }; | 210 | } |
211 | 211 | ||
212 | return Object.assign(obj, newProperties); | 212 | return Object.assign(obj, newProperties) |
213 | } | 213 | } |
214 | ); | 214 | ) |
215 | } | 215 | } |
216 | 216 | ||
217 | private handleLogin (obj: any) { | 217 | private handleLogin (obj: any) { |
218 | const id = obj.id; | 218 | const id = obj.id |
219 | const username = obj.username; | 219 | const username = obj.username |
220 | const role = obj.role; | 220 | const role = obj.role |
221 | const email = obj.email; | 221 | const email = obj.email |
222 | const displayNSFW = obj.displayNSFW; | 222 | const displayNSFW = obj.displayNSFW |
223 | const hashTokens = { | 223 | const hashTokens = { |
224 | access_token: obj.access_token, | 224 | accessToken: obj.access_token, |
225 | token_type: obj.token_type, | 225 | tokenType: obj.token_type, |
226 | refresh_token: obj.refresh_token | 226 | refreshToken: obj.refresh_token |
227 | }; | 227 | } |
228 | 228 | ||
229 | this.user = new AuthUser({ id, username, role, displayNSFW, email }, hashTokens); | 229 | this.user = new AuthUser({ id, username, role, displayNSFW, email }, hashTokens) |
230 | this.user.save(); | 230 | this.user.save() |
231 | 231 | ||
232 | this.setStatus(AuthStatus.LoggedIn); | 232 | this.setStatus(AuthStatus.LoggedIn) |
233 | } | 233 | } |
234 | 234 | ||
235 | private handleRefreshToken (obj: any) { | 235 | private handleRefreshToken (obj: any) { |
236 | this.user.refreshTokens(obj.access_token, obj.refresh_token); | 236 | this.user.refreshTokens(obj.access_token, obj.refresh_token) |
237 | this.user.save(); | 237 | this.user.save() |
238 | } | 238 | } |
239 | 239 | ||
240 | private setStatus(status: AuthStatus) { | 240 | private setStatus (status: AuthStatus) { |
241 | this.loginChanged.next(status); | 241 | this.loginChanged.next(status) |
242 | } | 242 | } |
243 | 243 | ||
244 | } | 244 | } |
diff --git a/client/src/app/core/auth/index.ts b/client/src/app/core/auth/index.ts index 67a18cfbb..8e5caa7ed 100644 --- a/client/src/app/core/auth/index.ts +++ b/client/src/app/core/auth/index.ts | |||
@@ -1,3 +1,3 @@ | |||
1 | export * from './auth-status.model'; | 1 | export * from './auth-status.model' |
2 | export * from './auth-user.model'; | 2 | export * from './auth-user.model' |
3 | export * from './auth.service' | 3 | export * from './auth.service' |
diff --git a/client/src/app/core/config/config.service.ts b/client/src/app/core/config/config.service.ts index 407dca083..a83ec61d2 100644 --- a/client/src/app/core/config/config.service.ts +++ b/client/src/app/core/config/config.service.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Http } from '@angular/http'; | 2 | import { Http } from '@angular/http' |
3 | 3 | ||
4 | import { RestExtractor } from '../../shared/rest'; | 4 | import { RestExtractor } from '../../shared/rest' |
5 | 5 | ||
6 | @Injectable() | 6 | @Injectable() |
7 | export class ConfigService { | 7 | export class ConfigService { |
8 | private static BASE_CONFIG_URL = API_URL + '/api/v1/config/'; | 8 | private static BASE_CONFIG_URL = API_URL + '/api/v1/config/' |
9 | 9 | ||
10 | private config: { | 10 | private config: { |
11 | signup: { | 11 | signup: { |
@@ -15,22 +15,22 @@ export class ConfigService { | |||
15 | signup: { | 15 | signup: { |
16 | enabled: false | 16 | enabled: false |
17 | } | 17 | } |
18 | }; | 18 | } |
19 | 19 | ||
20 | constructor( | 20 | constructor ( |
21 | private http: Http, | 21 | private http: Http, |
22 | private restExtractor: RestExtractor, | 22 | private restExtractor: RestExtractor |
23 | ) {} | 23 | ) {} |
24 | 24 | ||
25 | loadConfig() { | 25 | loadConfig () { |
26 | this.http.get(ConfigService.BASE_CONFIG_URL) | 26 | this.http.get(ConfigService.BASE_CONFIG_URL) |
27 | .map(this.restExtractor.extractDataGet) | 27 | .map(this.restExtractor.extractDataGet) |
28 | .subscribe(data => { | 28 | .subscribe(data => { |
29 | this.config = data; | 29 | this.config = data |
30 | }); | 30 | }) |
31 | } | 31 | } |
32 | 32 | ||
33 | getConfig() { | 33 | getConfig () { |
34 | return this.config; | 34 | return this.config |
35 | } | 35 | } |
36 | } | 36 | } |
diff --git a/client/src/app/core/config/index.ts b/client/src/app/core/config/index.ts index 90392254a..3724e12f2 100644 --- a/client/src/app/core/config/index.ts +++ b/client/src/app/core/config/index.ts | |||
@@ -1 +1 @@ | |||
export * from './config.service'; | export * from './config.service' | ||
diff --git a/client/src/app/core/confirm/confirm.component.ts b/client/src/app/core/confirm/confirm.component.ts index ae42ff68a..066e3fc5f 100644 --- a/client/src/app/core/confirm/confirm.component.ts +++ b/client/src/app/core/confirm/confirm.component.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { Component, HostListener, OnInit, ViewChild } from '@angular/core'; | 1 | import { Component, HostListener, OnInit, ViewChild } from '@angular/core' |
2 | 2 | ||
3 | import { ModalDirective } from 'ngx-bootstrap/modal'; | 3 | import { ModalDirective } from 'ngx-bootstrap/modal' |
4 | 4 | ||
5 | import { ConfirmService } from './confirm.service'; | 5 | import { ConfirmService } from './confirm.service' |
6 | 6 | ||
7 | export interface ConfigChangedEvent { | 7 | export interface ConfigChangedEvent { |
8 | columns: { [id: string]: { isDisplayed: boolean }; }; | 8 | columns: { [id: string]: { isDisplayed: boolean } } |
9 | config: { resultsPerPage: number }; | 9 | config: { resultsPerPage: number } |
10 | } | 10 | } |
11 | 11 | ||
12 | @Component({ | 12 | @Component({ |
@@ -14,48 +14,48 @@ export interface ConfigChangedEvent { | |||
14 | templateUrl: './confirm.component.html' | 14 | templateUrl: './confirm.component.html' |
15 | }) | 15 | }) |
16 | export class ConfirmComponent implements OnInit { | 16 | export class ConfirmComponent implements OnInit { |
17 | @ViewChild('confirmModal') confirmModal: ModalDirective; | 17 | @ViewChild('confirmModal') confirmModal: ModalDirective |
18 | 18 | ||
19 | title = ''; | 19 | title = '' |
20 | message = ''; | 20 | message = '' |
21 | 21 | ||
22 | constructor (private confirmService: ConfirmService) { | 22 | constructor (private confirmService: ConfirmService) { |
23 | // Empty | 23 | // Empty |
24 | } | 24 | } |
25 | 25 | ||
26 | ngOnInit() { | 26 | ngOnInit () { |
27 | this.confirmModal.config = { | 27 | this.confirmModal.config = { |
28 | backdrop: 'static', | 28 | backdrop: 'static', |
29 | keyboard: false | 29 | keyboard: false |
30 | }; | 30 | } |
31 | 31 | ||
32 | this.confirmService.showConfirm.subscribe( | 32 | this.confirmService.showConfirm.subscribe( |
33 | ({ title, message }) => { | 33 | ({ title, message }) => { |
34 | this.title = title; | 34 | this.title = title |
35 | this.message = message; | 35 | this.message = message |
36 | 36 | ||
37 | this.showModal(); | 37 | this.showModal() |
38 | } | 38 | } |
39 | ); | 39 | ) |
40 | } | 40 | } |
41 | 41 | ||
42 | @HostListener('keydown.enter') | 42 | @HostListener('keydown.enter') |
43 | confirm() { | 43 | confirm () { |
44 | this.confirmService.confirmResponse.next(true); | 44 | this.confirmService.confirmResponse.next(true) |
45 | this.hideModal(); | 45 | this.hideModal() |
46 | } | 46 | } |
47 | 47 | ||
48 | @HostListener('keydown.esc') | 48 | @HostListener('keydown.esc') |
49 | abort() { | 49 | abort () { |
50 | this.confirmService.confirmResponse.next(false); | 50 | this.confirmService.confirmResponse.next(false) |
51 | this.hideModal(); | 51 | this.hideModal() |
52 | } | 52 | } |
53 | 53 | ||
54 | showModal() { | 54 | showModal () { |
55 | this.confirmModal.show(); | 55 | this.confirmModal.show() |
56 | } | 56 | } |
57 | 57 | ||
58 | hideModal() { | 58 | hideModal () { |
59 | this.confirmModal.hide(); | 59 | this.confirmModal.hide() |
60 | } | 60 | } |
61 | } | 61 | } |
diff --git a/client/src/app/core/confirm/confirm.service.ts b/client/src/app/core/confirm/confirm.service.ts index 08127a66f..f12ff1848 100644 --- a/client/src/app/core/confirm/confirm.service.ts +++ b/client/src/app/core/confirm/confirm.service.ts | |||
@@ -1,15 +1,15 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Subject } from 'rxjs/Subject'; | 2 | import { Subject } from 'rxjs/Subject' |
3 | import 'rxjs/add/operator/first'; | 3 | import 'rxjs/add/operator/first' |
4 | 4 | ||
5 | @Injectable() | 5 | @Injectable() |
6 | export class ConfirmService { | 6 | export class ConfirmService { |
7 | showConfirm = new Subject<{ title, message }>(); | 7 | showConfirm = new Subject<{ title, message }>() |
8 | confirmResponse = new Subject<boolean>(); | 8 | confirmResponse = new Subject<boolean>() |
9 | 9 | ||
10 | confirm(message = '', title = '') { | 10 | confirm (message = '', title = '') { |
11 | this.showConfirm.next({ title, message }); | 11 | this.showConfirm.next({ title, message }) |
12 | 12 | ||
13 | return this.confirmResponse.asObservable().first(); | 13 | return this.confirmResponse.asObservable().first() |
14 | } | 14 | } |
15 | } | 15 | } |
diff --git a/client/src/app/core/confirm/index.ts b/client/src/app/core/confirm/index.ts index 789e7e547..44aabfc13 100644 --- a/client/src/app/core/confirm/index.ts +++ b/client/src/app/core/confirm/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './confirm.component'; | 1 | export * from './confirm.component' |
2 | export * from './confirm.service'; | 2 | export * from './confirm.service' |
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 81c8f2da6..382febe5c 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts | |||
@@ -1,16 +1,16 @@ | |||
1 | import { NgModule, Optional, SkipSelf } from '@angular/core'; | 1 | import { NgModule, Optional, SkipSelf } from '@angular/core' |
2 | import { CommonModule } from '@angular/common'; | 2 | import { CommonModule } from '@angular/common' |
3 | import { HttpModule } from '@angular/http'; | 3 | import { HttpModule } from '@angular/http' |
4 | import { RouterModule } from '@angular/router'; | 4 | import { RouterModule } from '@angular/router' |
5 | 5 | ||
6 | import { SimpleNotificationsModule } from 'angular2-notifications'; | 6 | import { SimpleNotificationsModule } from 'angular2-notifications' |
7 | import { ModalModule } from 'ngx-bootstrap/modal'; | 7 | import { ModalModule } from 'ngx-bootstrap/modal' |
8 | 8 | ||
9 | import { AuthService } from './auth'; | 9 | import { AuthService } from './auth' |
10 | import { ConfigService } from './config'; | 10 | import { ConfigService } from './config' |
11 | import { ConfirmComponent, ConfirmService } from './confirm'; | 11 | import { ConfirmComponent, ConfirmService } from './confirm' |
12 | import { MenuComponent, MenuAdminComponent } from './menu'; | 12 | import { MenuComponent, MenuAdminComponent } from './menu' |
13 | import { throwIfAlreadyLoaded } from './module-import-guard'; | 13 | import { throwIfAlreadyLoaded } from './module-import-guard' |
14 | 14 | ||
15 | @NgModule({ | 15 | @NgModule({ |
16 | imports: [ | 16 | imports: [ |
@@ -43,7 +43,7 @@ import { throwIfAlreadyLoaded } from './module-import-guard'; | |||
43 | ] | 43 | ] |
44 | }) | 44 | }) |
45 | export class CoreModule { | 45 | export class CoreModule { |
46 | constructor( @Optional() @SkipSelf() parentModule: CoreModule) { | 46 | constructor ( @Optional() @SkipSelf() parentModule: CoreModule) { |
47 | throwIfAlreadyLoaded(parentModule, 'CoreModule'); | 47 | throwIfAlreadyLoaded(parentModule, 'CoreModule') |
48 | } | 48 | } |
49 | } | 49 | } |
diff --git a/client/src/app/core/index.ts b/client/src/app/core/index.ts index 96b28658b..01b12ce7e 100644 --- a/client/src/app/core/index.ts +++ b/client/src/app/core/index.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export * from './auth'; | 1 | export * from './auth' |
2 | export * from './config'; | 2 | export * from './config' |
3 | export * from './confirm'; | 3 | export * from './confirm' |
4 | export * from './menu'; | 4 | export * from './menu' |
5 | export * from './core.module' | 5 | export * from './core.module' |
diff --git a/client/src/app/core/menu/index.ts b/client/src/app/core/menu/index.ts index ff40f26e1..c905ed20a 100644 --- a/client/src/app/core/menu/index.ts +++ b/client/src/app/core/menu/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './menu.component'; | 1 | export * from './menu.component' |
2 | export * from './menu-admin.component'; | 2 | export * from './menu-admin.component' |
diff --git a/client/src/app/core/menu/menu-admin.component.ts b/client/src/app/core/menu/menu-admin.component.ts index 236161fce..f6cc6554c 100644 --- a/client/src/app/core/menu/menu-admin.component.ts +++ b/client/src/app/core/menu/menu-admin.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | selector: 'my-menu-admin', | 4 | selector: 'my-menu-admin', |
diff --git a/client/src/app/core/menu/menu.component.ts b/client/src/app/core/menu/menu.component.ts index 5ab8bf464..b725f64a7 100644 --- a/client/src/app/core/menu/menu.component.ts +++ b/client/src/app/core/menu/menu.component.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { Router } from '@angular/router'; | 2 | import { Router } from '@angular/router' |
3 | 3 | ||
4 | import { AuthService, AuthStatus } from '../auth'; | 4 | import { AuthService, AuthStatus } from '../auth' |
5 | import { ConfigService } from '../config'; | 5 | import { ConfigService } from '../config' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-menu', | 8 | selector: 'my-menu', |
@@ -10,7 +10,7 @@ import { ConfigService } from '../config'; | |||
10 | styleUrls: [ './menu.component.scss' ] | 10 | styleUrls: [ './menu.component.scss' ] |
11 | }) | 11 | }) |
12 | export class MenuComponent implements OnInit { | 12 | export class MenuComponent implements OnInit { |
13 | isLoggedIn: boolean; | 13 | isLoggedIn: boolean |
14 | 14 | ||
15 | constructor ( | 15 | constructor ( |
16 | private authService: AuthService, | 16 | private authService: AuthService, |
@@ -18,35 +18,35 @@ export class MenuComponent implements OnInit { | |||
18 | private router: Router | 18 | private router: Router |
19 | ) {} | 19 | ) {} |
20 | 20 | ||
21 | ngOnInit() { | 21 | ngOnInit () { |
22 | this.isLoggedIn = this.authService.isLoggedIn(); | 22 | this.isLoggedIn = this.authService.isLoggedIn() |
23 | 23 | ||
24 | this.authService.loginChangedSource.subscribe( | 24 | this.authService.loginChangedSource.subscribe( |
25 | status => { | 25 | status => { |
26 | if (status === AuthStatus.LoggedIn) { | 26 | if (status === AuthStatus.LoggedIn) { |
27 | this.isLoggedIn = true; | 27 | this.isLoggedIn = true |
28 | console.log('Logged in.'); | 28 | console.log('Logged in.') |
29 | } else if (status === AuthStatus.LoggedOut) { | 29 | } else if (status === AuthStatus.LoggedOut) { |
30 | this.isLoggedIn = false; | 30 | this.isLoggedIn = false |
31 | console.log('Logged out.'); | 31 | console.log('Logged out.') |
32 | } else { | 32 | } else { |
33 | console.error('Unknown auth status: ' + status); | 33 | console.error('Unknown auth status: ' + status) |
34 | } | 34 | } |
35 | } | 35 | } |
36 | ); | 36 | ) |
37 | } | 37 | } |
38 | 38 | ||
39 | isRegistrationEnabled() { | 39 | isRegistrationEnabled () { |
40 | return this.configService.getConfig().signup.enabled; | 40 | return this.configService.getConfig().signup.enabled |
41 | } | 41 | } |
42 | 42 | ||
43 | isUserAdmin() { | 43 | isUserAdmin () { |
44 | return this.authService.isAdmin(); | 44 | return this.authService.isAdmin() |
45 | } | 45 | } |
46 | 46 | ||
47 | logout() { | 47 | logout () { |
48 | this.authService.logout(); | 48 | this.authService.logout() |
49 | // Redirect to home page | 49 | // Redirect to home page |
50 | this.router.navigate(['/videos/list']); | 50 | this.router.navigate(['/videos/list']) |
51 | } | 51 | } |
52 | } | 52 | } |
diff --git a/client/src/app/core/module-import-guard.ts b/client/src/app/core/module-import-guard.ts index 445640c4f..32b1d8f19 100644 --- a/client/src/app/core/module-import-guard.ts +++ b/client/src/app/core/module-import-guard.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export function throwIfAlreadyLoaded(parentModule: any, moduleName: string) { | 1 | export function throwIfAlreadyLoaded (parentModule: any, moduleName: string) { |
2 | if (parentModule) { | 2 | if (parentModule) { |
3 | throw new Error(`${moduleName} has already been loaded. Import Core modules in the AppModule only.`); | 3 | throw new Error(`${moduleName} has already been loaded. Import Core modules in the AppModule only.`) |
4 | } | 4 | } |
5 | } | 5 | } |
diff --git a/client/src/app/environment.ts b/client/src/app/environment.ts index 799102d82..dd327a62e 100644 --- a/client/src/app/environment.ts +++ b/client/src/app/environment.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | /* tslint:disable */ | ||
2 | |||
1 | /** | 3 | /** |
2 | * Angular 2 | 4 | * Angular 2 |
3 | */ | 5 | */ |
diff --git a/client/src/app/index.ts b/client/src/app/index.ts index da53f6aef..d45dbeff6 100644 --- a/client/src/app/index.ts +++ b/client/src/app/index.ts | |||
@@ -1 +1 @@ | |||
export * from './app.module'; | export * from './app.module' | ||
diff --git a/client/src/app/login/index.ts b/client/src/app/login/index.ts index 5639915f7..f1301d8b5 100644 --- a/client/src/app/login/index.ts +++ b/client/src/app/login/index.ts | |||
@@ -1,3 +1,3 @@ | |||
1 | export * from './login-routing.module'; | 1 | export * from './login-routing.module' |
2 | export * from './login.component'; | 2 | export * from './login.component' |
3 | export * from './login.module'; | 3 | export * from './login.module' |
diff --git a/client/src/app/login/login-routing.module.ts b/client/src/app/login/login-routing.module.ts index 371993884..1a91677c0 100644 --- a/client/src/app/login/login-routing.module.ts +++ b/client/src/app/login/login-routing.module.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router'; | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | 3 | ||
4 | import { LoginComponent } from './login.component'; | 4 | import { LoginComponent } from './login.component' |
5 | 5 | ||
6 | const loginRoutes: Routes = [ | 6 | const loginRoutes: Routes = [ |
7 | { | 7 | { |
@@ -13,7 +13,7 @@ const loginRoutes: Routes = [ | |||
13 | } | 13 | } |
14 | } | 14 | } |
15 | } | 15 | } |
16 | ]; | 16 | ] |
17 | 17 | ||
18 | @NgModule({ | 18 | @NgModule({ |
19 | imports: [ RouterModule.forChild(loginRoutes) ], | 19 | imports: [ RouterModule.forChild(loginRoutes) ], |
diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts index fd4a314cc..77703a80c 100644 --- a/client/src/app/login/login.component.ts +++ b/client/src/app/login/login.component.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup, Validators } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { AuthService } from '../core'; | 5 | import { AuthService } from '../core' |
6 | import { FormReactive } from '../shared'; | 6 | import { FormReactive } from '../shared' |
7 | 7 | ||
8 | @Component({ | 8 | @Component({ |
9 | selector: 'my-login', | 9 | selector: 'my-login', |
@@ -11,60 +11,60 @@ import { FormReactive } from '../shared'; | |||
11 | }) | 11 | }) |
12 | 12 | ||
13 | export class LoginComponent extends FormReactive implements OnInit { | 13 | export class LoginComponent extends FormReactive implements OnInit { |
14 | error: string = null; | 14 | error: string = null |
15 | 15 | ||
16 | form: FormGroup; | 16 | form: FormGroup |
17 | formErrors = { | 17 | formErrors = { |
18 | 'username': '', | 18 | 'username': '', |
19 | 'password': '' | 19 | 'password': '' |
20 | }; | 20 | } |
21 | validationMessages = { | 21 | validationMessages = { |
22 | 'username': { | 22 | 'username': { |
23 | 'required': 'Username is required.', | 23 | 'required': 'Username is required.' |
24 | }, | 24 | }, |
25 | 'password': { | 25 | 'password': { |
26 | 'required': 'Password is required.' | 26 | 'required': 'Password is required.' |
27 | } | 27 | } |
28 | }; | 28 | } |
29 | 29 | ||
30 | constructor( | 30 | constructor ( |
31 | private authService: AuthService, | 31 | private authService: AuthService, |
32 | private formBuilder: FormBuilder, | 32 | private formBuilder: FormBuilder, |
33 | private router: Router | 33 | private router: Router |
34 | ) { | 34 | ) { |
35 | super(); | 35 | super() |
36 | } | 36 | } |
37 | 37 | ||
38 | buildForm() { | 38 | buildForm () { |
39 | this.form = this.formBuilder.group({ | 39 | this.form = this.formBuilder.group({ |
40 | username: [ '', Validators.required ], | 40 | username: [ '', Validators.required ], |
41 | password: [ '', Validators.required ], | 41 | password: [ '', Validators.required ] |
42 | }); | 42 | }) |
43 | 43 | ||
44 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 44 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
45 | } | 45 | } |
46 | 46 | ||
47 | ngOnInit() { | 47 | ngOnInit () { |
48 | this.buildForm(); | 48 | this.buildForm() |
49 | } | 49 | } |
50 | 50 | ||
51 | login() { | 51 | login () { |
52 | this.error = null; | 52 | this.error = null |
53 | 53 | ||
54 | const { username, password } = this.form.value; | 54 | const { username, password } = this.form.value |
55 | 55 | ||
56 | this.authService.login(username, password).subscribe( | 56 | this.authService.login(username, password).subscribe( |
57 | result => this.router.navigate(['/videos/list']), | 57 | result => this.router.navigate(['/videos/list']), |
58 | 58 | ||
59 | error => { | 59 | error => { |
60 | console.error(error.json); | 60 | console.error(error.json) |
61 | 61 | ||
62 | if (error.json.error === 'invalid_grant') { | 62 | if (error.json.error === 'invalid_grant') { |
63 | this.error = 'Credentials are invalid.'; | 63 | this.error = 'Credentials are invalid.' |
64 | } else { | 64 | } else { |
65 | this.error = `${error.json.error}: ${error.json.error_description}`; | 65 | this.error = `${error.json.error}: ${error.json.error_description}` |
66 | } | 66 | } |
67 | } | 67 | } |
68 | ); | 68 | ) |
69 | } | 69 | } |
70 | } | 70 | } |
diff --git a/client/src/app/login/login.module.ts b/client/src/app/login/login.module.ts index 31a723b43..1de72dbaa 100644 --- a/client/src/app/login/login.module.ts +++ b/client/src/app/login/login.module.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | 2 | ||
3 | import { LoginRoutingModule } from './login-routing.module'; | 3 | import { LoginRoutingModule } from './login-routing.module' |
4 | import { LoginComponent } from './login.component'; | 4 | import { LoginComponent } from './login.component' |
5 | import { SharedModule } from '../shared'; | 5 | import { SharedModule } from '../shared' |
6 | 6 | ||
7 | @NgModule({ | 7 | @NgModule({ |
8 | imports: [ | 8 | imports: [ |
diff --git a/client/src/app/shared/auth/auth-http.service.ts b/client/src/app/shared/auth/auth-http.service.ts index c4114aa02..0fbaab0a8 100644 --- a/client/src/app/shared/auth/auth-http.service.ts +++ b/client/src/app/shared/auth/auth-http.service.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { | 2 | import { |
3 | ConnectionBackend, | 3 | ConnectionBackend, |
4 | Headers, | 4 | Headers, |
@@ -9,79 +9,79 @@ import { | |||
9 | RequestOptionsArgs, | 9 | RequestOptionsArgs, |
10 | Response, | 10 | Response, |
11 | XHRBackend | 11 | XHRBackend |
12 | } from '@angular/http'; | 12 | } from '@angular/http' |
13 | import { Observable } from 'rxjs/Observable'; | 13 | import { Observable } from 'rxjs/Observable' |
14 | 14 | ||
15 | import { AuthService } from '../../core'; | 15 | import { AuthService } from '../../core' |
16 | 16 | ||
17 | @Injectable() | 17 | @Injectable() |
18 | export class AuthHttp extends Http { | 18 | export class AuthHttp extends Http { |
19 | constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private authService: AuthService) { | 19 | constructor (backend: ConnectionBackend, defaultOptions: RequestOptions, private authService: AuthService) { |
20 | super(backend, defaultOptions); | 20 | super(backend, defaultOptions) |
21 | } | 21 | } |
22 | 22 | ||
23 | request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> { | 23 | request (url: string | Request, options?: RequestOptionsArgs): Observable<Response> { |
24 | if (!options) options = {}; | 24 | if (!options) options = {} |
25 | 25 | ||
26 | options.headers = new Headers(); | 26 | options.headers = new Headers() |
27 | this.setAuthorizationHeader(options.headers); | 27 | this.setAuthorizationHeader(options.headers) |
28 | 28 | ||
29 | return super.request(url, options) | 29 | return super.request(url, options) |
30 | .catch((err) => { | 30 | .catch((err) => { |
31 | if (err.status === 401) { | 31 | if (err.status === 401) { |
32 | return this.handleTokenExpired(url, options); | 32 | return this.handleTokenExpired(url, options) |
33 | } | 33 | } |
34 | 34 | ||
35 | return Observable.throw(err); | 35 | return Observable.throw(err) |
36 | }); | 36 | }) |
37 | } | 37 | } |
38 | 38 | ||
39 | delete(url: string, options?: RequestOptionsArgs): Observable<Response> { | 39 | delete (url: string, options?: RequestOptionsArgs): Observable<Response> { |
40 | if (!options) options = {}; | 40 | if (!options) options = {} |
41 | options.method = RequestMethod.Delete; | 41 | options.method = RequestMethod.Delete |
42 | 42 | ||
43 | return this.request(url, options); | 43 | return this.request(url, options) |
44 | } | 44 | } |
45 | 45 | ||
46 | get(url: string, options?: RequestOptionsArgs): Observable<Response> { | 46 | get (url: string, options?: RequestOptionsArgs): Observable<Response> { |
47 | if (!options) options = {}; | 47 | if (!options) options = {} |
48 | options.method = RequestMethod.Get; | 48 | options.method = RequestMethod.Get |
49 | 49 | ||
50 | return this.request(url, options); | 50 | return this.request(url, options) |
51 | } | 51 | } |
52 | 52 | ||
53 | post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> { | 53 | post (url: string, body: any, options?: RequestOptionsArgs): Observable<Response> { |
54 | if (!options) options = {}; | 54 | if (!options) options = {} |
55 | options.method = RequestMethod.Post; | 55 | options.method = RequestMethod.Post |
56 | options.body = body; | 56 | options.body = body |
57 | 57 | ||
58 | return this.request(url, options); | 58 | return this.request(url, options) |
59 | } | 59 | } |
60 | 60 | ||
61 | put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> { | 61 | put (url: string, body: any, options?: RequestOptionsArgs): Observable<Response> { |
62 | if (!options) options = {}; | 62 | if (!options) options = {} |
63 | options.method = RequestMethod.Put; | 63 | options.method = RequestMethod.Put |
64 | options.body = body; | 64 | options.body = body |
65 | 65 | ||
66 | return this.request(url, options); | 66 | return this.request(url, options) |
67 | } | 67 | } |
68 | 68 | ||
69 | private handleTokenExpired(url: string | Request, options: RequestOptionsArgs) { | 69 | private handleTokenExpired (url: string | Request, options: RequestOptionsArgs) { |
70 | return this.authService.refreshAccessToken() | 70 | return this.authService.refreshAccessToken() |
71 | .flatMap(() => { | 71 | .flatMap(() => { |
72 | this.setAuthorizationHeader(options.headers); | 72 | this.setAuthorizationHeader(options.headers) |
73 | 73 | ||
74 | return super.request(url, options); | 74 | return super.request(url, options) |
75 | }); | 75 | }) |
76 | } | 76 | } |
77 | 77 | ||
78 | private setAuthorizationHeader(headers: Headers) { | 78 | private setAuthorizationHeader (headers: Headers) { |
79 | headers.set('Authorization', this.authService.getRequestHeaderValue()); | 79 | headers.set('Authorization', this.authService.getRequestHeaderValue()) |
80 | } | 80 | } |
81 | } | 81 | } |
82 | 82 | ||
83 | export function useFactory(backend: XHRBackend, defaultOptions: RequestOptions, authService: AuthService) { | 83 | export function useFactory (backend: XHRBackend, defaultOptions: RequestOptions, authService: AuthService) { |
84 | return new AuthHttp(backend, defaultOptions, authService); | 84 | return new AuthHttp(backend, defaultOptions, authService) |
85 | } | 85 | } |
86 | 86 | ||
87 | export const AUTH_HTTP_PROVIDERS = [ | 87 | export const AUTH_HTTP_PROVIDERS = [ |
@@ -89,5 +89,5 @@ export const AUTH_HTTP_PROVIDERS = [ | |||
89 | provide: AuthHttp, | 89 | provide: AuthHttp, |
90 | useFactory, | 90 | useFactory, |
91 | deps: [ XHRBackend, RequestOptions, AuthService ] | 91 | deps: [ XHRBackend, RequestOptions, AuthService ] |
92 | }, | 92 | } |
93 | ]; | 93 | ] |
diff --git a/client/src/app/shared/auth/index.ts b/client/src/app/shared/auth/index.ts index c488aed69..0f2bfb0d6 100644 --- a/client/src/app/shared/auth/index.ts +++ b/client/src/app/shared/auth/index.ts | |||
@@ -1 +1 @@ | |||
export * from './auth-http.service'; | export * from './auth-http.service' | ||
diff --git a/client/src/app/shared/forms/form-reactive.ts b/client/src/app/shared/forms/form-reactive.ts index a5732e083..e7764d069 100644 --- a/client/src/app/shared/forms/form-reactive.ts +++ b/client/src/app/shared/forms/form-reactive.ts | |||
@@ -1,38 +1,38 @@ | |||
1 | import { FormGroup } from '@angular/forms'; | 1 | import { FormGroup } from '@angular/forms' |
2 | 2 | ||
3 | export abstract class FormReactive { | 3 | export abstract class FormReactive { |
4 | abstract form: FormGroup; | 4 | abstract form: FormGroup |
5 | abstract formErrors: Object; | 5 | abstract formErrors: Object |
6 | abstract validationMessages: Object; | 6 | abstract validationMessages: Object |
7 | 7 | ||
8 | abstract buildForm(): void; | 8 | abstract buildForm (): void |
9 | 9 | ||
10 | protected onValueChanged(data?: any) { | 10 | protected onValueChanged (data?: any) { |
11 | for (const field in this.formErrors) { | 11 | for (const field in this.formErrors) { |
12 | // clear previous error message (if any) | 12 | // clear previous error message (if any) |
13 | this.formErrors[field] = ''; | 13 | this.formErrors[field] = '' |
14 | const control = this.form.get(field); | 14 | const control = this.form.get(field) |
15 | 15 | ||
16 | if (control && control.dirty && !control.valid) { | 16 | if (control && control.dirty && !control.valid) { |
17 | const messages = this.validationMessages[field]; | 17 | const messages = this.validationMessages[field] |
18 | for (const key in control.errors) { | 18 | for (const key in control.errors) { |
19 | this.formErrors[field] += messages[key] + ' '; | 19 | this.formErrors[field] += messages[key] + ' ' |
20 | } | 20 | } |
21 | } | 21 | } |
22 | } | 22 | } |
23 | } | 23 | } |
24 | 24 | ||
25 | // Same as onValueChanged but force checking even if the field is not dirty | 25 | // Same as onValueChanged but force checking even if the field is not dirty |
26 | protected forceCheck() { | 26 | protected forceCheck () { |
27 | for (const field in this.formErrors) { | 27 | for (const field in this.formErrors) { |
28 | // clear previous error message (if any) | 28 | // clear previous error message (if any) |
29 | this.formErrors[field] = ''; | 29 | this.formErrors[field] = '' |
30 | const control = this.form.get(field); | 30 | const control = this.form.get(field) |
31 | 31 | ||
32 | if (control && !control.valid) { | 32 | if (control && !control.valid) { |
33 | const messages = this.validationMessages[field]; | 33 | const messages = this.validationMessages[field] |
34 | for (const key in control.errors) { | 34 | for (const key in control.errors) { |
35 | this.formErrors[field] += messages[key] + ' '; | 35 | this.formErrors[field] += messages[key] + ' ' |
36 | } | 36 | } |
37 | } | 37 | } |
38 | } | 38 | } |
diff --git a/client/src/app/shared/forms/form-validators/host.validator.ts b/client/src/app/shared/forms/form-validators/host.validator.ts index ec417e079..03e810fdb 100644 --- a/client/src/app/shared/forms/form-validators/host.validator.ts +++ b/client/src/app/shared/forms/form-validators/host.validator.ts | |||
@@ -1,14 +1,14 @@ | |||
1 | import { FormControl } from '@angular/forms'; | 1 | import { FormControl } from '@angular/forms' |
2 | 2 | ||
3 | export function validateHost(c: FormControl) { | 3 | export function validateHost (c: FormControl) { |
4 | // Thanks to http://stackoverflow.com/a/106223 | 4 | // Thanks to http://stackoverflow.com/a/106223 |
5 | const HOST_REGEXP = new RegExp( | 5 | const HOST_REGEXP = new RegExp( |
6 | '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' | 6 | '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' |
7 | ); | 7 | ) |
8 | 8 | ||
9 | return HOST_REGEXP.test(c.value) ? null : { | 9 | return HOST_REGEXP.test(c.value) ? null : { |
10 | validateHost: { | 10 | validateHost: { |
11 | valid: false | 11 | valid: false |
12 | } | 12 | } |
13 | }; | 13 | } |
14 | } | 14 | } |
diff --git a/client/src/app/shared/forms/form-validators/index.ts b/client/src/app/shared/forms/form-validators/index.ts index ab7c2df31..efe77d4ae 100644 --- a/client/src/app/shared/forms/form-validators/index.ts +++ b/client/src/app/shared/forms/form-validators/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './host.validator'; | 1 | export * from './host.validator' |
2 | export * from './user'; | 2 | export * from './user' |
3 | export * from './video-abuse'; | 3 | export * from './video-abuse' |
4 | export * from './video'; | 4 | export * from './video' |
diff --git a/client/src/app/shared/forms/form-validators/user.ts b/client/src/app/shared/forms/form-validators/user.ts index 259d2b868..fd316583e 100644 --- a/client/src/app/shared/forms/form-validators/user.ts +++ b/client/src/app/shared/forms/form-validators/user.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Validators } from '@angular/forms'; | 1 | import { Validators } from '@angular/forms' |
2 | 2 | ||
3 | export const USER_USERNAME = { | 3 | export const USER_USERNAME = { |
4 | VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(20) ], | 4 | VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(20) ], |
@@ -7,18 +7,18 @@ export const USER_USERNAME = { | |||
7 | 'minlength': 'Username must be at least 3 characters long.', | 7 | 'minlength': 'Username must be at least 3 characters long.', |
8 | 'maxlength': 'Username cannot be more than 20 characters long.' | 8 | 'maxlength': 'Username cannot be more than 20 characters long.' |
9 | } | 9 | } |
10 | }; | 10 | } |
11 | export const USER_EMAIL = { | 11 | export const USER_EMAIL = { |
12 | VALIDATORS: [ Validators.required, Validators.email ], | 12 | VALIDATORS: [ Validators.required, Validators.email ], |
13 | MESSAGES: { | 13 | MESSAGES: { |
14 | 'required': 'Email is required.', | 14 | 'required': 'Email is required.', |
15 | 'email': 'Email must be valid.', | 15 | 'email': 'Email must be valid.' |
16 | } | 16 | } |
17 | }; | 17 | } |
18 | export const USER_PASSWORD = { | 18 | export const USER_PASSWORD = { |
19 | VALIDATORS: [ Validators.required, Validators.minLength(6) ], | 19 | VALIDATORS: [ Validators.required, Validators.minLength(6) ], |
20 | MESSAGES: { | 20 | MESSAGES: { |
21 | 'required': 'Password is required.', | 21 | 'required': 'Password is required.', |
22 | 'minlength': 'Password must be at least 6 characters long.', | 22 | 'minlength': 'Password must be at least 6 characters long.' |
23 | } | 23 | } |
24 | }; | 24 | } |
diff --git a/client/src/app/shared/forms/form-validators/video-abuse.ts b/client/src/app/shared/forms/form-validators/video-abuse.ts index 94a29a3b7..3c7f26205 100644 --- a/client/src/app/shared/forms/form-validators/video-abuse.ts +++ b/client/src/app/shared/forms/form-validators/video-abuse.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Validators } from '@angular/forms'; | 1 | import { Validators } from '@angular/forms' |
2 | 2 | ||
3 | export const VIDEO_ABUSE_REASON = { | 3 | export const VIDEO_ABUSE_REASON = { |
4 | VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ], | 4 | VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(300) ], |
@@ -7,4 +7,4 @@ export const VIDEO_ABUSE_REASON = { | |||
7 | 'minlength': 'Report reson must be at least 2 characters long.', | 7 | 'minlength': 'Report reson must be at least 2 characters long.', |
8 | 'maxlength': 'Report reson cannot be more than 300 characters long.' | 8 | 'maxlength': 'Report reson cannot be more than 300 characters long.' |
9 | } | 9 | } |
10 | }; | 10 | } |
diff --git a/client/src/app/shared/forms/form-validators/video.ts b/client/src/app/shared/forms/form-validators/video.ts index f7e4e5e4b..6542cf8f6 100644 --- a/client/src/app/shared/forms/form-validators/video.ts +++ b/client/src/app/shared/forms/form-validators/video.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Validators } from '@angular/forms'; | 1 | import { Validators } from '@angular/forms' |
2 | 2 | ||
3 | export const VIDEO_NAME = { | 3 | export const VIDEO_NAME = { |
4 | VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(50) ], | 4 | VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(50) ], |
@@ -7,26 +7,26 @@ export const VIDEO_NAME = { | |||
7 | 'minlength': 'Video name must be at least 3 characters long.', | 7 | 'minlength': 'Video name must be at least 3 characters long.', |
8 | 'maxlength': 'Video name cannot be more than 50 characters long.' | 8 | 'maxlength': 'Video name cannot be more than 50 characters long.' |
9 | } | 9 | } |
10 | }; | 10 | } |
11 | 11 | ||
12 | export const VIDEO_CATEGORY = { | 12 | export const VIDEO_CATEGORY = { |
13 | VALIDATORS: [ Validators.required ], | 13 | VALIDATORS: [ Validators.required ], |
14 | MESSAGES: { | 14 | MESSAGES: { |
15 | 'required': 'Video category is required.' | 15 | 'required': 'Video category is required.' |
16 | } | 16 | } |
17 | }; | 17 | } |
18 | 18 | ||
19 | export const VIDEO_LICENCE = { | 19 | export const VIDEO_LICENCE = { |
20 | VALIDATORS: [ Validators.required ], | 20 | VALIDATORS: [ Validators.required ], |
21 | MESSAGES: { | 21 | MESSAGES: { |
22 | 'required': 'Video licence is required.' | 22 | 'required': 'Video licence is required.' |
23 | } | 23 | } |
24 | }; | 24 | } |
25 | 25 | ||
26 | export const VIDEO_LANGUAGE = { | 26 | export const VIDEO_LANGUAGE = { |
27 | VALIDATORS: [ ], | 27 | VALIDATORS: [ ], |
28 | MESSAGES: {} | 28 | MESSAGES: {} |
29 | }; | 29 | } |
30 | 30 | ||
31 | export const VIDEO_DESCRIPTION = { | 31 | export const VIDEO_DESCRIPTION = { |
32 | VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(250) ], | 32 | VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(250) ], |
@@ -35,7 +35,7 @@ export const VIDEO_DESCRIPTION = { | |||
35 | 'minlength': 'Video description must be at least 3 characters long.', | 35 | 'minlength': 'Video description must be at least 3 characters long.', |
36 | 'maxlength': 'Video description cannot be more than 250 characters long.' | 36 | 'maxlength': 'Video description cannot be more than 250 characters long.' |
37 | } | 37 | } |
38 | }; | 38 | } |
39 | 39 | ||
40 | export const VIDEO_TAGS = { | 40 | export const VIDEO_TAGS = { |
41 | VALIDATORS: [ Validators.minLength(2), Validators.maxLength(10) ], | 41 | VALIDATORS: [ Validators.minLength(2), Validators.maxLength(10) ], |
@@ -43,4 +43,4 @@ export const VIDEO_TAGS = { | |||
43 | 'minlength': 'A tag should be more than 2 characters long.', | 43 | 'minlength': 'A tag should be more than 2 characters long.', |
44 | 'maxlength': 'A tag should be less than 10 characters long.' | 44 | 'maxlength': 'A tag should be less than 10 characters long.' |
45 | } | 45 | } |
46 | }; | 46 | } |
diff --git a/client/src/app/shared/forms/index.ts b/client/src/app/shared/forms/index.ts index 588ebb4be..7464bb022 100644 --- a/client/src/app/shared/forms/index.ts +++ b/client/src/app/shared/forms/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './form-validators'; | 1 | export * from './form-validators' |
2 | export * from './form-reactive'; | 2 | export * from './form-reactive' |
diff --git a/client/src/app/shared/index.ts b/client/src/app/shared/index.ts index 61e8ed523..212645c51 100644 --- a/client/src/app/shared/index.ts +++ b/client/src/app/shared/index.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | export * from './auth'; | 1 | export * from './auth' |
2 | export * from './forms'; | 2 | export * from './forms' |
3 | export * from './rest'; | 3 | export * from './rest' |
4 | export * from './search'; | 4 | export * from './search' |
5 | export * from './users'; | 5 | export * from './users' |
6 | export * from './video-abuse'; | 6 | export * from './video-abuse' |
7 | export * from './shared.module'; | 7 | export * from './shared.module' |
8 | export * from './utils'; | 8 | export * from './utils' |
diff --git a/client/src/app/shared/rest/index.ts b/client/src/app/shared/rest/index.ts index 3cb123c3b..e0be155cf 100644 --- a/client/src/app/shared/rest/index.ts +++ b/client/src/app/shared/rest/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './rest-data-source'; | 1 | export * from './rest-data-source' |
2 | export * from './rest-extractor.service'; | 2 | export * from './rest-extractor.service' |
3 | export * from './rest-pagination'; | 3 | export * from './rest-pagination' |
4 | export * from './rest.service'; | 4 | export * from './rest.service' |
diff --git a/client/src/app/shared/rest/rest-data-source.ts b/client/src/app/shared/rest/rest-data-source.ts index 1def38c73..2ef5d38da 100644 --- a/client/src/app/shared/rest/rest-data-source.ts +++ b/client/src/app/shared/rest/rest-data-source.ts | |||
@@ -1,51 +1,51 @@ | |||
1 | import { Http, RequestOptionsArgs, URLSearchParams, } from '@angular/http'; | 1 | import { Http, RequestOptionsArgs, URLSearchParams, Response } from '@angular/http' |
2 | 2 | ||
3 | import { ServerDataSource } from 'ng2-smart-table'; | 3 | import { ServerDataSource } from 'ng2-smart-table' |
4 | 4 | ||
5 | export class RestDataSource extends ServerDataSource { | 5 | export class RestDataSource extends ServerDataSource { |
6 | constructor(http: Http, endpoint: string) { | 6 | constructor (http: Http, endpoint: string) { |
7 | const options = { | 7 | const options = { |
8 | endPoint: endpoint, | 8 | endPoint: endpoint, |
9 | sortFieldKey: 'sort', | 9 | sortFieldKey: 'sort', |
10 | dataKey: 'data' | 10 | dataKey: 'data' |
11 | }; | 11 | } |
12 | 12 | ||
13 | super(http, options); | 13 | super(http, options) |
14 | } | 14 | } |
15 | 15 | ||
16 | protected extractTotalFromResponse(res) { | 16 | protected extractTotalFromResponse (res: Response) { |
17 | const rawData = res.json(); | 17 | const rawData = res.json() |
18 | return rawData ? parseInt(rawData.total) : 0; | 18 | return rawData ? parseInt(rawData.total, 10) : 0 |
19 | } | 19 | } |
20 | 20 | ||
21 | protected addSortRequestOptions(requestOptions: RequestOptionsArgs) { | 21 | protected addSortRequestOptions (requestOptions: RequestOptionsArgs) { |
22 | let searchParams: URLSearchParams = <URLSearchParams> requestOptions.search; | 22 | const searchParams = requestOptions.search as URLSearchParams |
23 | 23 | ||
24 | if (this.sortConf) { | 24 | if (this.sortConf) { |
25 | this.sortConf.forEach((fieldConf) => { | 25 | this.sortConf.forEach((fieldConf) => { |
26 | const sortPrefix = fieldConf.direction === 'desc' ? '-' : ''; | 26 | const sortPrefix = fieldConf.direction === 'desc' ? '-' : '' |
27 | 27 | ||
28 | searchParams.set(this.conf.sortFieldKey, sortPrefix + fieldConf.field); | 28 | searchParams.set(this.conf.sortFieldKey, sortPrefix + fieldConf.field) |
29 | }); | 29 | }) |
30 | } | 30 | } |
31 | 31 | ||
32 | return requestOptions; | 32 | return requestOptions |
33 | } | 33 | } |
34 | 34 | ||
35 | protected addPagerRequestOptions(requestOptions: RequestOptionsArgs) { | 35 | protected addPagerRequestOptions (requestOptions: RequestOptionsArgs) { |
36 | let searchParams: URLSearchParams = <URLSearchParams> requestOptions.search; | 36 | const searchParams = requestOptions.search as URLSearchParams |
37 | 37 | ||
38 | if (this.pagingConf && this.pagingConf['page'] && this.pagingConf['perPage']) { | 38 | if (this.pagingConf && this.pagingConf['page'] && this.pagingConf['perPage']) { |
39 | const perPage = this.pagingConf['perPage']; | 39 | const perPage = this.pagingConf['perPage'] |
40 | const page = this.pagingConf['page']; | 40 | const page = this.pagingConf['page'] |
41 | 41 | ||
42 | const start = (page - 1) * perPage; | 42 | const start = (page - 1) * perPage |
43 | const count = perPage; | 43 | const count = perPage |
44 | 44 | ||
45 | searchParams.set('start', start.toString()); | 45 | searchParams.set('start', start.toString()) |
46 | searchParams.set('count', count.toString()); | 46 | searchParams.set('count', count.toString()) |
47 | } | 47 | } |
48 | 48 | ||
49 | return requestOptions; | 49 | return requestOptions |
50 | } | 50 | } |
51 | } | 51 | } |
diff --git a/client/src/app/shared/rest/rest-extractor.service.ts b/client/src/app/shared/rest/rest-extractor.service.ts index fcb1598f4..f6a818ec8 100644 --- a/client/src/app/shared/rest/rest-extractor.service.ts +++ b/client/src/app/shared/rest/rest-extractor.service.ts | |||
@@ -1,52 +1,52 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Response } from '@angular/http'; | 2 | import { Response } from '@angular/http' |
3 | import { Observable } from 'rxjs/Observable'; | 3 | import { Observable } from 'rxjs/Observable' |
4 | 4 | ||
5 | export interface ResultList { | 5 | export interface ResultList { |
6 | data: any[]; | 6 | data: any[] |
7 | total: number; | 7 | total: number |
8 | } | 8 | } |
9 | 9 | ||
10 | @Injectable() | 10 | @Injectable() |
11 | export class RestExtractor { | 11 | export class RestExtractor { |
12 | 12 | ||
13 | constructor () { ; } | 13 | extractDataBool (res: Response) { |
14 | 14 | return true | |
15 | extractDataBool(res: Response) { | ||
16 | return true; | ||
17 | } | 15 | } |
18 | 16 | ||
19 | extractDataList(res: Response) { | 17 | extractDataList (res: Response) { |
20 | const body = res.json(); | 18 | const body = res.json() |
21 | 19 | ||
22 | const ret: ResultList = { | 20 | const ret: ResultList = { |
23 | data: body.data, | 21 | data: body.data, |
24 | total: body.total | 22 | total: body.total |
25 | }; | 23 | } |
26 | 24 | ||
27 | return ret; | 25 | return ret |
28 | } | 26 | } |
29 | 27 | ||
30 | extractDataGet(res: Response) { | 28 | extractDataGet (res: Response) { |
31 | return res.json(); | 29 | return res.json() |
32 | } | 30 | } |
33 | 31 | ||
34 | handleError(res: Response) { | 32 | handleError (res: Response) { |
35 | let text = 'Server error: '; | 33 | let text = 'Server error: ' |
36 | text += res.text(); | 34 | text += res.text() |
37 | let json = ''; | 35 | let json = '' |
38 | 36 | ||
39 | try { | 37 | try { |
40 | json = res.json(); | 38 | json = res.json() |
41 | } catch (err) { ; } | 39 | } catch (err) { |
40 | console.error('Cannot get JSON from response.') | ||
41 | } | ||
42 | 42 | ||
43 | const error = { | 43 | const error = { |
44 | json, | 44 | json, |
45 | text | 45 | text |
46 | }; | 46 | } |
47 | 47 | ||
48 | console.error(error); | 48 | console.error(error) |
49 | 49 | ||
50 | return Observable.throw(error); | 50 | return Observable.throw(error) |
51 | } | 51 | } |
52 | } | 52 | } |
diff --git a/client/src/app/shared/rest/rest-pagination.ts b/client/src/app/shared/rest/rest-pagination.ts index 0cfa4f468..766e7a9e5 100644 --- a/client/src/app/shared/rest/rest-pagination.ts +++ b/client/src/app/shared/rest/rest-pagination.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface RestPagination { | 1 | export interface RestPagination { |
2 | currentPage: number; | 2 | currentPage: number |
3 | itemsPerPage: number; | 3 | itemsPerPage: number |
4 | totalItems: number; | 4 | totalItems: number |
5 | }; | 5 | } |
diff --git a/client/src/app/shared/rest/rest.service.ts b/client/src/app/shared/rest/rest.service.ts index 16b47e957..43dc20b34 100644 --- a/client/src/app/shared/rest/rest.service.ts +++ b/client/src/app/shared/rest/rest.service.ts | |||
@@ -1,27 +1,27 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { URLSearchParams } from '@angular/http'; | 2 | import { URLSearchParams } from '@angular/http' |
3 | 3 | ||
4 | import { RestPagination } from './rest-pagination'; | 4 | import { RestPagination } from './rest-pagination' |
5 | 5 | ||
6 | @Injectable() | 6 | @Injectable() |
7 | export class RestService { | 7 | export class RestService { |
8 | 8 | ||
9 | buildRestGetParams(pagination?: RestPagination, sort?: string) { | 9 | buildRestGetParams (pagination?: RestPagination, sort?: string) { |
10 | const params = new URLSearchParams(); | 10 | const params = new URLSearchParams() |
11 | 11 | ||
12 | if (pagination) { | 12 | if (pagination) { |
13 | const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage; | 13 | const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage |
14 | const count: number = pagination.itemsPerPage; | 14 | const count: number = pagination.itemsPerPage |
15 | 15 | ||
16 | params.set('start', start.toString()); | 16 | params.set('start', start.toString()) |
17 | params.set('count', count.toString()); | 17 | params.set('count', count.toString()) |
18 | } | 18 | } |
19 | 19 | ||
20 | if (sort) { | 20 | if (sort) { |
21 | params.set('sort', sort); | 21 | params.set('sort', sort) |
22 | } | 22 | } |
23 | 23 | ||
24 | return params; | 24 | return params |
25 | } | 25 | } |
26 | 26 | ||
27 | } | 27 | } |
diff --git a/client/src/app/shared/search/index.ts b/client/src/app/shared/search/index.ts index a897ed099..d4016cf89 100644 --- a/client/src/app/shared/search/index.ts +++ b/client/src/app/shared/search/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './search-field.type'; | 1 | export * from './search-field.type' |
2 | export * from './search.component'; | 2 | export * from './search.component' |
3 | export * from './search.model'; | 3 | export * from './search.model' |
4 | export * from './search.service'; | 4 | export * from './search.service' |
diff --git a/client/src/app/shared/search/search-field.type.ts b/client/src/app/shared/search/search-field.type.ts index 6be584ed1..63557898a 100644 --- a/client/src/app/shared/search/search-field.type.ts +++ b/client/src/app/shared/search/search-field.type.ts | |||
@@ -1 +1 @@ | |||
export type SearchField = "name" | "author" | "host" | "magnetUri" | "tags"; | export type SearchField = 'name' | 'author' | 'host' | 'magnetUri' | 'tags' | ||
diff --git a/client/src/app/shared/search/search.component.ts b/client/src/app/shared/search/search.component.ts index 48413b4f2..ecce20666 100644 --- a/client/src/app/shared/search/search.component.ts +++ b/client/src/app/shared/search/search.component.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { Router } from '@angular/router'; | 2 | import { Router } from '@angular/router' |
3 | 3 | ||
4 | import { Search } from './search.model'; | 4 | import { Search } from './search.model' |
5 | import { SearchField } from './search-field.type'; | 5 | import { SearchField } from './search-field.type' |
6 | import { SearchService } from './search.service'; | 6 | import { SearchService } from './search.service' |
7 | 7 | ||
8 | @Component({ | 8 | @Component({ |
9 | selector: 'my-search', | 9 | selector: 'my-search', |
@@ -18,53 +18,53 @@ export class SearchComponent implements OnInit { | |||
18 | host: 'Pod Host', | 18 | host: 'Pod Host', |
19 | magnetUri: 'Magnet URI', | 19 | magnetUri: 'Magnet URI', |
20 | tags: 'Tags' | 20 | tags: 'Tags' |
21 | }; | 21 | } |
22 | searchCriterias: Search = { | 22 | searchCriterias: Search = { |
23 | field: 'name', | 23 | field: 'name', |
24 | value: '' | 24 | value: '' |
25 | }; | 25 | } |
26 | 26 | ||
27 | constructor(private searchService: SearchService, private router: Router) {} | 27 | constructor (private searchService: SearchService, private router: Router) {} |
28 | 28 | ||
29 | ngOnInit() { | 29 | ngOnInit () { |
30 | // Subscribe if the search changed | 30 | // Subscribe if the search changed |
31 | // Usually changed by videos list component | 31 | // Usually changed by videos list component |
32 | this.searchService.updateSearch.subscribe( | 32 | this.searchService.updateSearch.subscribe( |
33 | newSearchCriterias => { | 33 | newSearchCriterias => { |
34 | // Put a field by default | 34 | // Put a field by default |
35 | if (!newSearchCriterias.field) { | 35 | if (!newSearchCriterias.field) { |
36 | newSearchCriterias.field = 'name'; | 36 | newSearchCriterias.field = 'name' |
37 | } | 37 | } |
38 | 38 | ||
39 | this.searchCriterias = newSearchCriterias; | 39 | this.searchCriterias = newSearchCriterias |
40 | } | 40 | } |
41 | ); | 41 | ) |
42 | } | 42 | } |
43 | 43 | ||
44 | get choiceKeys() { | 44 | get choiceKeys () { |
45 | return Object.keys(this.fieldChoices); | 45 | return Object.keys(this.fieldChoices) |
46 | } | 46 | } |
47 | 47 | ||
48 | choose($event: MouseEvent, choice: SearchField) { | 48 | choose ($event: MouseEvent, choice: SearchField) { |
49 | $event.preventDefault(); | 49 | $event.preventDefault() |
50 | $event.stopPropagation(); | 50 | $event.stopPropagation() |
51 | 51 | ||
52 | this.searchCriterias.field = choice; | 52 | this.searchCriterias.field = choice |
53 | 53 | ||
54 | if (this.searchCriterias.value) { | 54 | if (this.searchCriterias.value) { |
55 | this.doSearch(); | 55 | this.doSearch() |
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
59 | doSearch() { | 59 | doSearch () { |
60 | if (this.router.url.indexOf('/videos/list') === -1) { | 60 | if (this.router.url.indexOf('/videos/list') === -1) { |
61 | this.router.navigate([ '/videos/list' ]); | 61 | this.router.navigate([ '/videos/list' ]) |
62 | } | 62 | } |
63 | 63 | ||
64 | this.searchService.searchUpdated.next(this.searchCriterias); | 64 | this.searchService.searchUpdated.next(this.searchCriterias) |
65 | } | 65 | } |
66 | 66 | ||
67 | getStringChoice(choiceKey: SearchField) { | 67 | getStringChoice (choiceKey: SearchField) { |
68 | return this.fieldChoices[choiceKey]; | 68 | return this.fieldChoices[choiceKey] |
69 | } | 69 | } |
70 | } | 70 | } |
diff --git a/client/src/app/shared/search/search.model.ts b/client/src/app/shared/search/search.model.ts index 932a6566c..174adf2c6 100644 --- a/client/src/app/shared/search/search.model.ts +++ b/client/src/app/shared/search/search.model.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { SearchField } from './search-field.type'; | 1 | import { SearchField } from './search-field.type' |
2 | 2 | ||
3 | export interface Search { | 3 | export interface Search { |
4 | field: SearchField; | 4 | field: SearchField |
5 | value: string; | 5 | value: string |
6 | } | 6 | } |
diff --git a/client/src/app/shared/search/search.service.ts b/client/src/app/shared/search/search.service.ts index 717a7fa50..0480b46bd 100644 --- a/client/src/app/shared/search/search.service.ts +++ b/client/src/app/shared/search/search.service.ts | |||
@@ -1,18 +1,18 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Subject } from 'rxjs/Subject'; | 2 | import { Subject } from 'rxjs/Subject' |
3 | import { ReplaySubject } from 'rxjs/ReplaySubject'; | 3 | import { ReplaySubject } from 'rxjs/ReplaySubject' |
4 | 4 | ||
5 | import { Search } from './search.model'; | 5 | import { Search } from './search.model' |
6 | 6 | ||
7 | // This class is needed to communicate between videos/ and search component | 7 | // This class is needed to communicate between videos/ and search component |
8 | // Remove it when we'll be able to subscribe to router changes | 8 | // Remove it when we'll be able to subscribe to router changes |
9 | @Injectable() | 9 | @Injectable() |
10 | export class SearchService { | 10 | export class SearchService { |
11 | searchUpdated: Subject<Search>; | 11 | searchUpdated: Subject<Search> |
12 | updateSearch: Subject<Search>; | 12 | updateSearch: Subject<Search> |
13 | 13 | ||
14 | constructor() { | 14 | constructor () { |
15 | this.updateSearch = new Subject<Search>(); | 15 | this.updateSearch = new Subject<Search>() |
16 | this.searchUpdated = new ReplaySubject<Search>(1); | 16 | this.searchUpdated = new ReplaySubject<Search>(1) |
17 | } | 17 | } |
18 | } | 18 | } |
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 8ffaf964b..99b51aa4e 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -1,23 +1,23 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { CommonModule } from '@angular/common'; | 2 | import { CommonModule } from '@angular/common' |
3 | import { HttpModule } from '@angular/http'; | 3 | import { HttpModule } from '@angular/http' |
4 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | 4 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' |
5 | import { RouterModule } from '@angular/router'; | 5 | import { RouterModule } from '@angular/router' |
6 | 6 | ||
7 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; | 7 | import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe' |
8 | import { KeysPipe } from 'angular-pipes/src/object/keys.pipe'; | 8 | import { KeysPipe } from 'angular-pipes/src/object/keys.pipe' |
9 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; | 9 | import { BsDropdownModule } from 'ngx-bootstrap/dropdown' |
10 | import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; | 10 | import { ProgressbarModule } from 'ngx-bootstrap/progressbar' |
11 | import { PaginationModule } from 'ngx-bootstrap/pagination'; | 11 | import { PaginationModule } from 'ngx-bootstrap/pagination' |
12 | import { ModalModule } from 'ngx-bootstrap/modal'; | 12 | import { ModalModule } from 'ngx-bootstrap/modal' |
13 | import { FileUploadModule } from 'ng2-file-upload/ng2-file-upload'; | 13 | import { FileUploadModule } from 'ng2-file-upload/ng2-file-upload' |
14 | import { Ng2SmartTableModule } from 'ng2-smart-table'; | 14 | import { Ng2SmartTableModule } from 'ng2-smart-table' |
15 | 15 | ||
16 | import { AUTH_HTTP_PROVIDERS } from './auth'; | 16 | import { AUTH_HTTP_PROVIDERS } from './auth' |
17 | import { RestExtractor, RestService } from './rest'; | 17 | import { RestExtractor, RestService } from './rest' |
18 | import { SearchComponent, SearchService } from './search'; | 18 | import { SearchComponent, SearchService } from './search' |
19 | import { UserService } from './users'; | 19 | import { UserService } from './users' |
20 | import { VideoAbuseService } from './video-abuse'; | 20 | import { VideoAbuseService } from './video-abuse' |
21 | 21 | ||
22 | @NgModule({ | 22 | @NgModule({ |
23 | imports: [ | 23 | imports: [ |
diff --git a/client/src/app/shared/users/index.ts b/client/src/app/shared/users/index.ts index ff009e89b..7b5a67bc7 100644 --- a/client/src/app/shared/users/index.ts +++ b/client/src/app/shared/users/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './user.model'; | 1 | export * from './user.model' |
2 | export * from './user.service'; | 2 | export * from './user.service' |
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts index d4695ab67..1c2b481e3 100644 --- a/client/src/app/shared/users/user.model.ts +++ b/client/src/app/shared/users/user.model.ts | |||
@@ -1,33 +1,33 @@ | |||
1 | import { User as UserServerModel, UserRole } from '../../../../../shared'; | 1 | import { User as UserServerModel, UserRole } from '../../../../../shared' |
2 | 2 | ||
3 | export class User implements UserServerModel { | 3 | export class User implements UserServerModel { |
4 | id: number; | 4 | id: number |
5 | username: string; | 5 | username: string |
6 | email: string; | 6 | email: string |
7 | role: UserRole; | 7 | role: UserRole |
8 | displayNSFW: boolean; | 8 | displayNSFW: boolean |
9 | createdAt: Date; | 9 | createdAt: Date |
10 | 10 | ||
11 | constructor(hash: { | 11 | constructor (hash: { |
12 | id: number, | 12 | id: number, |
13 | username: string, | 13 | username: string, |
14 | email: string, | 14 | email: string, |
15 | role: UserRole, | 15 | role: UserRole, |
16 | displayNSFW?: boolean, | 16 | displayNSFW?: boolean, |
17 | createdAt?: Date, | 17 | createdAt?: Date |
18 | }) { | 18 | }) { |
19 | this.id = hash.id; | 19 | this.id = hash.id |
20 | this.username = hash.username; | 20 | this.username = hash.username |
21 | this.email = hash.email; | 21 | this.email = hash.email |
22 | this.role = hash.role; | 22 | this.role = hash.role |
23 | this.displayNSFW = hash.displayNSFW; | 23 | this.displayNSFW = hash.displayNSFW |
24 | 24 | ||
25 | if (hash.createdAt) { | 25 | if (hash.createdAt) { |
26 | this.createdAt = hash.createdAt; | 26 | this.createdAt = hash.createdAt |
27 | } | 27 | } |
28 | } | 28 | } |
29 | 29 | ||
30 | isAdmin() { | 30 | isAdmin () { |
31 | return this.role === 'admin'; | 31 | return this.role === 'admin' |
32 | } | 32 | } |
33 | } | 33 | } |
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts index f1265be0a..e956df5b1 100644 --- a/client/src/app/shared/users/user.service.ts +++ b/client/src/app/shared/users/user.service.ts | |||
@@ -1,58 +1,58 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Http } from '@angular/http'; | 2 | import { Http } from '@angular/http' |
3 | import 'rxjs/add/operator/catch'; | 3 | import 'rxjs/add/operator/catch' |
4 | import 'rxjs/add/operator/map'; | 4 | import 'rxjs/add/operator/map' |
5 | 5 | ||
6 | import { AuthService } from '../../core'; | 6 | import { AuthService } from '../../core' |
7 | import { AuthHttp } from '../auth'; | 7 | import { AuthHttp } from '../auth' |
8 | import { RestExtractor } from '../rest'; | 8 | import { RestExtractor } from '../rest' |
9 | 9 | ||
10 | @Injectable() | 10 | @Injectable() |
11 | export class UserService { | 11 | export class UserService { |
12 | static BASE_USERS_URL = API_URL + '/api/v1/users/'; | 12 | static BASE_USERS_URL = API_URL + '/api/v1/users/' |
13 | 13 | ||
14 | constructor( | 14 | constructor ( |
15 | private http: Http, | 15 | private http: Http, |
16 | private authHttp: AuthHttp, | 16 | private authHttp: AuthHttp, |
17 | private authService: AuthService, | 17 | private authService: AuthService, |
18 | private restExtractor: RestExtractor | 18 | private restExtractor: RestExtractor |
19 | ) {} | 19 | ) {} |
20 | 20 | ||
21 | checkTokenValidity() { | 21 | checkTokenValidity () { |
22 | const url = UserService.BASE_USERS_URL + 'me'; | 22 | const url = UserService.BASE_USERS_URL + 'me' |
23 | 23 | ||
24 | // AuthHttp will redirect us to the login page if the oken is not valid anymore | 24 | // AuthHttp will redirect us to the login page if the oken is not valid anymore |
25 | this.authHttp.get(url).subscribe(() => { ; }); | 25 | this.authHttp.get(url).subscribe() |
26 | } | 26 | } |
27 | 27 | ||
28 | changePassword(newPassword: string) { | 28 | changePassword (newPassword: string) { |
29 | const url = UserService.BASE_USERS_URL + this.authService.getUser().id; | 29 | const url = UserService.BASE_USERS_URL + this.authService.getUser().id |
30 | const body = { | 30 | const body = { |
31 | password: newPassword | 31 | password: newPassword |
32 | }; | 32 | } |
33 | 33 | ||
34 | return this.authHttp.put(url, body) | 34 | return this.authHttp.put(url, body) |
35 | .map(this.restExtractor.extractDataBool) | 35 | .map(this.restExtractor.extractDataBool) |
36 | .catch((res) => this.restExtractor.handleError(res)); | 36 | .catch((res) => this.restExtractor.handleError(res)) |
37 | } | 37 | } |
38 | 38 | ||
39 | updateDetails(details: { displayNSFW: boolean }) { | 39 | updateDetails (details: { displayNSFW: boolean }) { |
40 | const url = UserService.BASE_USERS_URL + this.authService.getUser().id; | 40 | const url = UserService.BASE_USERS_URL + this.authService.getUser().id |
41 | 41 | ||
42 | return this.authHttp.put(url, details) | 42 | return this.authHttp.put(url, details) |
43 | .map(this.restExtractor.extractDataBool) | 43 | .map(this.restExtractor.extractDataBool) |
44 | .catch((res) => this.restExtractor.handleError(res)); | 44 | .catch((res) => this.restExtractor.handleError(res)) |
45 | } | 45 | } |
46 | 46 | ||
47 | signup(username: string, password: string, email: string) { | 47 | signup (username: string, password: string, email: string) { |
48 | const body = { | 48 | const body = { |
49 | username, | 49 | username, |
50 | email, | 50 | email, |
51 | password | 51 | password |
52 | }; | 52 | } |
53 | 53 | ||
54 | return this.http.post(UserService.BASE_USERS_URL + 'register', body) | 54 | return this.http.post(UserService.BASE_USERS_URL + 'register', body) |
55 | .map(this.restExtractor.extractDataBool) | 55 | .map(this.restExtractor.extractDataBool) |
56 | .catch(this.restExtractor.handleError); | 56 | .catch(this.restExtractor.handleError) |
57 | } | 57 | } |
58 | } | 58 | } |
diff --git a/client/src/app/shared/utils.ts b/client/src/app/shared/utils.ts index 5ab41fe5a..832311f89 100644 --- a/client/src/app/shared/utils.ts +++ b/client/src/app/shared/utils.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { DatePipe } from '@angular/common'; | 1 | import { DatePipe } from '@angular/common' |
2 | 2 | ||
3 | export class Utils { | 3 | export class Utils { |
4 | 4 | ||
5 | static dateToHuman(date: String) { | 5 | static dateToHuman (date: String) { |
6 | return new DatePipe('en').transform(date, 'medium'); | 6 | return new DatePipe('en').transform(date, 'medium') |
7 | } | 7 | } |
8 | 8 | ||
9 | static getRowDeleteButton() { | 9 | static getRowDeleteButton () { |
10 | return '<span class="glyphicon glyphicon-remove glyphicon-black"></span>'; | 10 | return '<span class="glyphicon glyphicon-remove glyphicon-black"></span>' |
11 | } | 11 | } |
12 | } | 12 | } |
diff --git a/client/src/app/shared/video-abuse/index.ts b/client/src/app/shared/video-abuse/index.ts index 563533ba5..7cf24c87d 100644 --- a/client/src/app/shared/video-abuse/index.ts +++ b/client/src/app/shared/video-abuse/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './video-abuse.service'; | 1 | export * from './video-abuse.service' |
2 | export * from './video-abuse.model'; | 2 | export * from './video-abuse.model' |
diff --git a/client/src/app/shared/video-abuse/video-abuse.model.ts b/client/src/app/shared/video-abuse/video-abuse.model.ts index bb0373027..49c87d6b8 100644 --- a/client/src/app/shared/video-abuse/video-abuse.model.ts +++ b/client/src/app/shared/video-abuse/video-abuse.model.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | export interface VideoAbuse { | 1 | export interface VideoAbuse { |
2 | id: string; | 2 | id: string |
3 | reason: string; | 3 | reason: string |
4 | reporterPodHost: string; | 4 | reporterPodHost: string |
5 | reporterUsername: string; | 5 | reporterUsername: string |
6 | videoId: string; | 6 | videoId: string |
7 | createdAt: Date; | 7 | createdAt: Date |
8 | } | 8 | } |
diff --git a/client/src/app/shared/video-abuse/video-abuse.service.ts b/client/src/app/shared/video-abuse/video-abuse.service.ts index da7b2ef8a..4317f9353 100644 --- a/client/src/app/shared/video-abuse/video-abuse.service.ts +++ b/client/src/app/shared/video-abuse/video-abuse.service.ts | |||
@@ -1,42 +1,42 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Http } from '@angular/http'; | 2 | import { Http } from '@angular/http' |
3 | import { Observable } from 'rxjs/Observable'; | 3 | import { Observable } from 'rxjs/Observable' |
4 | import 'rxjs/add/operator/catch'; | 4 | import 'rxjs/add/operator/catch' |
5 | import 'rxjs/add/operator/map'; | 5 | import 'rxjs/add/operator/map' |
6 | 6 | ||
7 | import { AuthService } from '../core'; | 7 | import { AuthService } from '../core' |
8 | import { AuthHttp } from '../auth'; | 8 | import { AuthHttp } from '../auth' |
9 | import { RestDataSource, RestExtractor, ResultList } from '../rest'; | 9 | import { RestDataSource, RestExtractor, ResultList } from '../rest' |
10 | import { VideoAbuse } from './video-abuse.model'; | 10 | import { VideoAbuse } from './video-abuse.model' |
11 | 11 | ||
12 | @Injectable() | 12 | @Injectable() |
13 | export class VideoAbuseService { | 13 | export class VideoAbuseService { |
14 | private static BASE_VIDEO_ABUSE_URL = API_URL + '/api/v1/videos/'; | 14 | private static BASE_VIDEO_ABUSE_URL = API_URL + '/api/v1/videos/' |
15 | 15 | ||
16 | constructor( | 16 | constructor ( |
17 | private authHttp: AuthHttp, | 17 | private authHttp: AuthHttp, |
18 | private restExtractor: RestExtractor | 18 | private restExtractor: RestExtractor |
19 | ) {} | 19 | ) {} |
20 | 20 | ||
21 | getDataSource() { | 21 | getDataSource () { |
22 | return new RestDataSource(this.authHttp, VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse'); | 22 | return new RestDataSource(this.authHttp, VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse') |
23 | } | 23 | } |
24 | 24 | ||
25 | reportVideo(id: string, reason: string) { | 25 | reportVideo (id: string, reason: string) { |
26 | const body = { | 26 | const body = { |
27 | reason | 27 | reason |
28 | }; | 28 | } |
29 | const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse'; | 29 | const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse' |
30 | 30 | ||
31 | return this.authHttp.post(url, body) | 31 | return this.authHttp.post(url, body) |
32 | .map(this.restExtractor.extractDataBool) | 32 | .map(this.restExtractor.extractDataBool) |
33 | .catch((res) => this.restExtractor.handleError(res)); | 33 | .catch((res) => this.restExtractor.handleError(res)) |
34 | } | 34 | } |
35 | 35 | ||
36 | private extractVideoAbuses(result: ResultList) { | 36 | private extractVideoAbuses (result: ResultList) { |
37 | const videoAbuses: VideoAbuse[] = result.data; | 37 | const videoAbuses: VideoAbuse[] = result.data |
38 | const totalVideoAbuses = result.total; | 38 | const totalVideoAbuses = result.total |
39 | 39 | ||
40 | return { videoAbuses, totalVideoAbuses }; | 40 | return { videoAbuses, totalVideoAbuses } |
41 | } | 41 | } |
42 | } | 42 | } |
diff --git a/client/src/app/signup/index.ts b/client/src/app/signup/index.ts index 1f4290ab5..b0aca9723 100644 --- a/client/src/app/signup/index.ts +++ b/client/src/app/signup/index.ts | |||
@@ -1,3 +1,3 @@ | |||
1 | export * from './signup-routing.module'; | 1 | export * from './signup-routing.module' |
2 | export * from './signup.component'; | 2 | export * from './signup.component' |
3 | export * from './signup.module'; | 3 | export * from './signup.module' |
diff --git a/client/src/app/signup/signup-routing.module.ts b/client/src/app/signup/signup-routing.module.ts index 367eed90c..122d6c976 100644 --- a/client/src/app/signup/signup-routing.module.ts +++ b/client/src/app/signup/signup-routing.module.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router'; | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | 3 | ||
4 | import { SignupComponent } from './signup.component'; | 4 | import { SignupComponent } from './signup.component' |
5 | 5 | ||
6 | const signupRoutes: Routes = [ | 6 | const signupRoutes: Routes = [ |
7 | { | 7 | { |
@@ -13,7 +13,7 @@ const signupRoutes: Routes = [ | |||
13 | } | 13 | } |
14 | } | 14 | } |
15 | } | 15 | } |
16 | ]; | 16 | ] |
17 | 17 | ||
18 | @NgModule({ | 18 | @NgModule({ |
19 | imports: [ RouterModule.forChild(signupRoutes) ], | 19 | imports: [ RouterModule.forChild(signupRoutes) ], |
diff --git a/client/src/app/signup/signup.component.ts b/client/src/app/signup/signup.component.ts index 85f93793b..bcbc8ded3 100644 --- a/client/src/app/signup/signup.component.ts +++ b/client/src/app/signup/signup.component.ts | |||
@@ -1,72 +1,72 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup, Validators } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { AuthService } from '../core'; | 7 | import { AuthService } from '../core' |
8 | import { | 8 | import { |
9 | FormReactive, | 9 | FormReactive, |
10 | UserService, | 10 | UserService, |
11 | USER_USERNAME, | 11 | USER_USERNAME, |
12 | USER_EMAIL, | 12 | USER_EMAIL, |
13 | USER_PASSWORD | 13 | USER_PASSWORD |
14 | } from '../shared'; | 14 | } from '../shared' |
15 | 15 | ||
16 | @Component({ | 16 | @Component({ |
17 | selector: 'my-signup', | 17 | selector: 'my-signup', |
18 | templateUrl: './signup.component.html' | 18 | templateUrl: './signup.component.html' |
19 | }) | 19 | }) |
20 | export class SignupComponent extends FormReactive implements OnInit { | 20 | export class SignupComponent extends FormReactive implements OnInit { |
21 | error: string = null; | 21 | error: string = null |
22 | 22 | ||
23 | form: FormGroup; | 23 | form: FormGroup |
24 | formErrors = { | 24 | formErrors = { |
25 | 'username': '', | 25 | 'username': '', |
26 | 'email': '', | 26 | 'email': '', |
27 | 'password': '' | 27 | 'password': '' |
28 | }; | 28 | } |
29 | validationMessages = { | 29 | validationMessages = { |
30 | 'username': USER_USERNAME.MESSAGES, | 30 | 'username': USER_USERNAME.MESSAGES, |
31 | 'email': USER_EMAIL.MESSAGES, | 31 | 'email': USER_EMAIL.MESSAGES, |
32 | 'password': USER_PASSWORD.MESSAGES, | 32 | 'password': USER_PASSWORD.MESSAGES |
33 | }; | 33 | } |
34 | 34 | ||
35 | constructor( | 35 | constructor ( |
36 | private formBuilder: FormBuilder, | 36 | private formBuilder: FormBuilder, |
37 | private router: Router, | 37 | private router: Router, |
38 | private notificationsService: NotificationsService, | 38 | private notificationsService: NotificationsService, |
39 | private userService: UserService | 39 | private userService: UserService |
40 | ) { | 40 | ) { |
41 | super(); | 41 | super() |
42 | } | 42 | } |
43 | 43 | ||
44 | buildForm() { | 44 | buildForm () { |
45 | this.form = this.formBuilder.group({ | 45 | this.form = this.formBuilder.group({ |
46 | username: [ '', USER_USERNAME.VALIDATORS ], | 46 | username: [ '', USER_USERNAME.VALIDATORS ], |
47 | email: [ '', USER_EMAIL.VALIDATORS ], | 47 | email: [ '', USER_EMAIL.VALIDATORS ], |
48 | password: [ '', USER_PASSWORD.VALIDATORS ], | 48 | password: [ '', USER_PASSWORD.VALIDATORS ] |
49 | }); | 49 | }) |
50 | 50 | ||
51 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 51 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
52 | } | 52 | } |
53 | 53 | ||
54 | ngOnInit() { | 54 | ngOnInit () { |
55 | this.buildForm(); | 55 | this.buildForm() |
56 | } | 56 | } |
57 | 57 | ||
58 | signup() { | 58 | signup () { |
59 | this.error = null; | 59 | this.error = null |
60 | 60 | ||
61 | const { username, password, email } = this.form.value; | 61 | const { username, password, email } = this.form.value |
62 | 62 | ||
63 | this.userService.signup(username, password, email).subscribe( | 63 | this.userService.signup(username, password, email).subscribe( |
64 | () => { | 64 | () => { |
65 | this.notificationsService.success('Success', `Registration for ${username} complete.`); | 65 | this.notificationsService.success('Success', `Registration for ${username} complete.`) |
66 | this.router.navigate([ '/videos/list' ]); | 66 | this.router.navigate([ '/videos/list' ]) |
67 | }, | 67 | }, |
68 | 68 | ||
69 | err => this.error = err.text | 69 | err => this.error = err.text |
70 | ); | 70 | ) |
71 | } | 71 | } |
72 | } | 72 | } |
diff --git a/client/src/app/signup/signup.module.ts b/client/src/app/signup/signup.module.ts index acb7e5515..61560ddcf 100644 --- a/client/src/app/signup/signup.module.ts +++ b/client/src/app/signup/signup.module.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | 2 | ||
3 | import { SignupRoutingModule } from './signup-routing.module'; | 3 | import { SignupRoutingModule } from './signup-routing.module' |
4 | import { SignupComponent } from './signup.component'; | 4 | import { SignupComponent } from './signup.component' |
5 | import { SharedModule } from '../shared'; | 5 | import { SharedModule } from '../shared' |
6 | 6 | ||
7 | @NgModule({ | 7 | @NgModule({ |
8 | imports: [ | 8 | imports: [ |
diff --git a/client/src/app/videos/index.ts b/client/src/app/videos/index.ts index 5158a23f8..83edcc758 100644 --- a/client/src/app/videos/index.ts +++ b/client/src/app/videos/index.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | export * from './shared'; | 1 | export * from './shared' |
2 | export * from './video-edit'; | 2 | export * from './video-edit' |
3 | export * from './video-list'; | 3 | export * from './video-list' |
4 | export * from './video-watch'; | 4 | export * from './video-watch' |
5 | export * from './videos-routing.module'; | 5 | export * from './videos-routing.module' |
6 | export * from './videos.component'; | 6 | export * from './videos.component' |
7 | export * from './videos.module'; | 7 | export * from './videos.module' |
diff --git a/client/src/app/videos/shared/index.ts b/client/src/app/videos/shared/index.ts index a68491022..0fa14f641 100644 --- a/client/src/app/videos/shared/index.ts +++ b/client/src/app/videos/shared/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './sort-field.type'; | 1 | export * from './sort-field.type' |
2 | export * from './rate-type.type'; | 2 | export * from './rate-type.type' |
3 | export * from './video.model'; | 3 | export * from './video.model' |
4 | export * from './video.service'; | 4 | export * from './video.service' |
diff --git a/client/src/app/videos/shared/rate-type.type.ts b/client/src/app/videos/shared/rate-type.type.ts index 88034d1ff..20eea3ae5 100644 --- a/client/src/app/videos/shared/rate-type.type.ts +++ b/client/src/app/videos/shared/rate-type.type.ts | |||
@@ -1 +1 @@ | |||
export type RateType = 'like' | 'dislike'; | export type RateType = 'like' | 'dislike' | ||
diff --git a/client/src/app/videos/shared/sort-field.type.ts b/client/src/app/videos/shared/sort-field.type.ts index 6cc598d8b..776f360f8 100644 --- a/client/src/app/videos/shared/sort-field.type.ts +++ b/client/src/app/videos/shared/sort-field.type.ts | |||
@@ -2,5 +2,4 @@ export type SortField = 'name' | '-name' | |||
2 | | 'duration' | '-duration' | 2 | | 'duration' | '-duration' |
3 | | 'createdAt' | '-createdAt' | 3 | | 'createdAt' | '-createdAt' |
4 | | 'views' | '-views' | 4 | | 'views' | '-views' |
5 | | 'likes' | '-likes'; | 5 | | 'likes' | '-likes' |
6 | |||
diff --git a/client/src/app/videos/shared/video.model.ts b/client/src/app/videos/shared/video.model.ts index e897eb175..f5e16fc13 100644 --- a/client/src/app/videos/shared/video.model.ts +++ b/client/src/app/videos/shared/video.model.ts | |||
@@ -1,56 +1,56 @@ | |||
1 | import { Video as VideoServerModel } from '../../../../../shared'; | 1 | import { Video as VideoServerModel } from '../../../../../shared' |
2 | import { User } from '../../shared'; | 2 | import { User } from '../../shared' |
3 | 3 | ||
4 | export class Video implements VideoServerModel { | 4 | export class Video implements VideoServerModel { |
5 | author: string; | 5 | author: string |
6 | by: string; | 6 | by: string |
7 | createdAt: Date; | 7 | createdAt: Date |
8 | categoryLabel: string; | 8 | categoryLabel: string |
9 | category: number; | 9 | category: number |
10 | licenceLabel: string; | 10 | licenceLabel: string |
11 | licence: number; | 11 | licence: number |
12 | languageLabel: string; | 12 | languageLabel: string |
13 | language: number; | 13 | language: number |
14 | description: string; | 14 | description: string |
15 | duration: number; | 15 | duration: number |
16 | durationLabel: string; | 16 | durationLabel: string |
17 | id: string; | 17 | id: string |
18 | isLocal: boolean; | 18 | isLocal: boolean |
19 | magnetUri: string; | 19 | magnetUri: string |
20 | name: string; | 20 | name: string |
21 | podHost: string; | 21 | podHost: string |
22 | tags: string[]; | 22 | tags: string[] |
23 | thumbnailPath: string; | 23 | thumbnailPath: string |
24 | thumbnailUrl: string; | 24 | thumbnailUrl: string |
25 | views: number; | 25 | views: number |
26 | likes: number; | 26 | likes: number |
27 | dislikes: number; | 27 | dislikes: number |
28 | nsfw: boolean; | 28 | nsfw: boolean |
29 | 29 | ||
30 | private static createByString(author: string, podHost: string) { | 30 | private static createByString (author: string, podHost: string) { |
31 | return author + '@' + podHost; | 31 | return author + '@' + podHost |
32 | } | 32 | } |
33 | 33 | ||
34 | private static createDurationString(duration: number) { | 34 | private static createDurationString (duration: number) { |
35 | const minutes = Math.floor(duration / 60); | 35 | const minutes = Math.floor(duration / 60) |
36 | const seconds = duration % 60; | 36 | const seconds = duration % 60 |
37 | const minutes_padding = minutes >= 10 ? '' : '0'; | 37 | const minutesPadding = minutes >= 10 ? '' : '0' |
38 | const seconds_padding = seconds >= 10 ? '' : '0'; | 38 | const secondsPadding = seconds >= 10 ? '' : '0' |
39 | 39 | ||
40 | return minutes_padding + minutes.toString() + ':' + seconds_padding + seconds.toString(); | 40 | return minutesPadding + minutes.toString() + ':' + secondsPadding + seconds.toString() |
41 | } | 41 | } |
42 | 42 | ||
43 | constructor(hash: { | 43 | constructor (hash: { |
44 | author: string, | 44 | author: string, |
45 | createdAt: string, | 45 | createdAt: string, |
46 | categoryLabel: string, | 46 | categoryLabel: string, |
47 | category: number, | 47 | category: number, |
48 | licenceLabel: string, | 48 | licenceLabel: string, |
49 | licence: number, | 49 | licence: number, |
50 | languageLabel: string; | 50 | languageLabel: string |
51 | language: number; | 51 | language: number |
52 | description: string, | 52 | description: string, |
53 | duration: number; | 53 | duration: number |
54 | id: string, | 54 | id: string, |
55 | isLocal: boolean, | 55 | isLocal: boolean, |
56 | magnetUri: string, | 56 | magnetUri: string, |
@@ -63,57 +63,57 @@ export class Video implements VideoServerModel { | |||
63 | dislikes: number, | 63 | dislikes: number, |
64 | nsfw: boolean | 64 | nsfw: boolean |
65 | }) { | 65 | }) { |
66 | this.author = hash.author; | 66 | this.author = hash.author |
67 | this.createdAt = new Date(hash.createdAt); | 67 | this.createdAt = new Date(hash.createdAt) |
68 | this.categoryLabel = hash.categoryLabel; | 68 | this.categoryLabel = hash.categoryLabel |
69 | this.category = hash.category; | 69 | this.category = hash.category |
70 | this.licenceLabel = hash.licenceLabel; | 70 | this.licenceLabel = hash.licenceLabel |
71 | this.licence = hash.licence; | 71 | this.licence = hash.licence |
72 | this.languageLabel = hash.languageLabel; | 72 | this.languageLabel = hash.languageLabel |
73 | this.language = hash.language; | 73 | this.language = hash.language |
74 | this.description = hash.description; | 74 | this.description = hash.description |
75 | this.duration = hash.duration; | 75 | this.duration = hash.duration |
76 | this.durationLabel = Video.createDurationString(hash.duration); | 76 | this.durationLabel = Video.createDurationString(hash.duration) |
77 | this.id = hash.id; | 77 | this.id = hash.id |
78 | this.isLocal = hash.isLocal; | 78 | this.isLocal = hash.isLocal |
79 | this.magnetUri = hash.magnetUri; | 79 | this.magnetUri = hash.magnetUri |
80 | this.name = hash.name; | 80 | this.name = hash.name |
81 | this.podHost = hash.podHost; | 81 | this.podHost = hash.podHost |
82 | this.tags = hash.tags; | 82 | this.tags = hash.tags |
83 | this.thumbnailPath = hash.thumbnailPath; | 83 | this.thumbnailPath = hash.thumbnailPath |
84 | this.thumbnailUrl = API_URL + hash.thumbnailPath; | 84 | this.thumbnailUrl = API_URL + hash.thumbnailPath |
85 | this.views = hash.views; | 85 | this.views = hash.views |
86 | this.likes = hash.likes; | 86 | this.likes = hash.likes |
87 | this.dislikes = hash.dislikes; | 87 | this.dislikes = hash.dislikes |
88 | this.nsfw = hash.nsfw; | 88 | this.nsfw = hash.nsfw |
89 | 89 | ||
90 | this.by = Video.createByString(hash.author, hash.podHost); | 90 | this.by = Video.createByString(hash.author, hash.podHost) |
91 | } | 91 | } |
92 | 92 | ||
93 | isRemovableBy(user) { | 93 | isRemovableBy (user) { |
94 | return user && this.isLocal === true && (this.author === user.username || user.isAdmin() === true); | 94 | return user && this.isLocal === true && (this.author === user.username || user.isAdmin() === true) |
95 | } | 95 | } |
96 | 96 | ||
97 | isBlackistableBy(user) { | 97 | isBlackistableBy (user) { |
98 | return user && user.isAdmin() === true && this.isLocal === false; | 98 | return user && user.isAdmin() === true && this.isLocal === false |
99 | } | 99 | } |
100 | 100 | ||
101 | isUpdatableBy(user) { | 101 | isUpdatableBy (user) { |
102 | return user && this.isLocal === true && user.username === this.author; | 102 | return user && this.isLocal === true && user.username === this.author |
103 | } | 103 | } |
104 | 104 | ||
105 | isVideoNSFWForUser(user: User) { | 105 | isVideoNSFWForUser (user: User) { |
106 | // If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos... | 106 | // If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos... |
107 | return (this.nsfw && (!user || user.displayNSFW === false)); | 107 | return (this.nsfw && (!user || user.displayNSFW === false)) |
108 | } | 108 | } |
109 | 109 | ||
110 | patch(values: Object) { | 110 | patch (values: Object) { |
111 | Object.keys(values).forEach((key) => { | 111 | Object.keys(values).forEach((key) => { |
112 | this[key] = values[key]; | 112 | this[key] = values[key] |
113 | }); | 113 | }) |
114 | } | 114 | } |
115 | 115 | ||
116 | toJSON() { | 116 | toJSON () { |
117 | return { | 117 | return { |
118 | author: this.author, | 118 | author: this.author, |
119 | createdAt: this.createdAt, | 119 | createdAt: this.createdAt, |
@@ -133,6 +133,6 @@ export class Video implements VideoServerModel { | |||
133 | likes: this.likes, | 133 | likes: this.likes, |
134 | dislikes: this.dislikes, | 134 | dislikes: this.dislikes, |
135 | nsfw: this.nsfw | 135 | nsfw: this.nsfw |
136 | }; | 136 | } |
137 | } | 137 | } |
138 | } | 138 | } |
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts index a53ea1064..a4e3d16df 100644 --- a/client/src/app/videos/shared/video.service.ts +++ b/client/src/app/videos/shared/video.service.ts | |||
@@ -1,13 +1,13 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Http, Headers, RequestOptions } from '@angular/http'; | 2 | import { Http, Headers, RequestOptions } from '@angular/http' |
3 | import { Observable } from 'rxjs/Observable'; | 3 | import { Observable } from 'rxjs/Observable' |
4 | import 'rxjs/add/operator/catch'; | 4 | import 'rxjs/add/operator/catch' |
5 | import 'rxjs/add/operator/map'; | 5 | import 'rxjs/add/operator/map' |
6 | 6 | ||
7 | import { Search } from '../../shared'; | 7 | import { Search } from '../../shared' |
8 | import { SortField } from './sort-field.type'; | 8 | import { SortField } from './sort-field.type' |
9 | import { RateType } from './rate-type.type'; | 9 | import { RateType } from './rate-type.type' |
10 | import { AuthService } from '../../core'; | 10 | import { AuthService } from '../../core' |
11 | import { | 11 | import { |
12 | AuthHttp, | 12 | AuthHttp, |
13 | RestExtractor, | 13 | RestExtractor, |
@@ -15,18 +15,18 @@ import { | |||
15 | RestService, | 15 | RestService, |
16 | ResultList, | 16 | ResultList, |
17 | UserService | 17 | UserService |
18 | } from '../../shared'; | 18 | } from '../../shared' |
19 | import { Video } from './video.model'; | 19 | import { Video } from './video.model' |
20 | 20 | ||
21 | @Injectable() | 21 | @Injectable() |
22 | export class VideoService { | 22 | export class VideoService { |
23 | private static BASE_VIDEO_URL = API_URL + '/api/v1/videos/'; | 23 | private static BASE_VIDEO_URL = API_URL + '/api/v1/videos/' |
24 | 24 | ||
25 | videoCategories: Array<{ id: number, label: string }> = []; | 25 | videoCategories: Array<{ id: number, label: string }> = [] |
26 | videoLicences: Array<{ id: number, label: string }> = []; | 26 | videoLicences: Array<{ id: number, label: string }> = [] |
27 | videoLanguages: Array<{ id: number, label: string }> = []; | 27 | videoLanguages: Array<{ id: number, label: string }> = [] |
28 | 28 | ||
29 | constructor( | 29 | constructor ( |
30 | private authService: AuthService, | 30 | private authService: AuthService, |
31 | private authHttp: AuthHttp, | 31 | private authHttp: AuthHttp, |
32 | private http: Http, | 32 | private http: Http, |
@@ -34,54 +34,54 @@ export class VideoService { | |||
34 | private restService: RestService | 34 | private restService: RestService |
35 | ) {} | 35 | ) {} |
36 | 36 | ||
37 | loadVideoCategories() { | 37 | loadVideoCategories () { |
38 | return this.http.get(VideoService.BASE_VIDEO_URL + 'categories') | 38 | return this.http.get(VideoService.BASE_VIDEO_URL + 'categories') |
39 | .map(this.restExtractor.extractDataGet) | 39 | .map(this.restExtractor.extractDataGet) |
40 | .subscribe(data => { | 40 | .subscribe(data => { |
41 | Object.keys(data).forEach(categoryKey => { | 41 | Object.keys(data).forEach(categoryKey => { |
42 | this.videoCategories.push({ | 42 | this.videoCategories.push({ |
43 | id: parseInt(categoryKey), | 43 | id: parseInt(categoryKey, 10), |
44 | label: data[categoryKey] | 44 | label: data[categoryKey] |
45 | }); | 45 | }) |
46 | }); | 46 | }) |
47 | }); | 47 | }) |
48 | } | 48 | } |
49 | 49 | ||
50 | loadVideoLicences() { | 50 | loadVideoLicences () { |
51 | return this.http.get(VideoService.BASE_VIDEO_URL + 'licences') | 51 | return this.http.get(VideoService.BASE_VIDEO_URL + 'licences') |
52 | .map(this.restExtractor.extractDataGet) | 52 | .map(this.restExtractor.extractDataGet) |
53 | .subscribe(data => { | 53 | .subscribe(data => { |
54 | Object.keys(data).forEach(licenceKey => { | 54 | Object.keys(data).forEach(licenceKey => { |
55 | this.videoLicences.push({ | 55 | this.videoLicences.push({ |
56 | id: parseInt(licenceKey), | 56 | id: parseInt(licenceKey, 10), |
57 | label: data[licenceKey] | 57 | label: data[licenceKey] |
58 | }); | 58 | }) |
59 | }); | 59 | }) |
60 | }); | 60 | }) |
61 | } | 61 | } |
62 | 62 | ||
63 | loadVideoLanguages() { | 63 | loadVideoLanguages () { |
64 | return this.http.get(VideoService.BASE_VIDEO_URL + 'languages') | 64 | return this.http.get(VideoService.BASE_VIDEO_URL + 'languages') |
65 | .map(this.restExtractor.extractDataGet) | 65 | .map(this.restExtractor.extractDataGet) |
66 | .subscribe(data => { | 66 | .subscribe(data => { |
67 | Object.keys(data).forEach(languageKey => { | 67 | Object.keys(data).forEach(languageKey => { |
68 | this.videoLanguages.push({ | 68 | this.videoLanguages.push({ |
69 | id: parseInt(languageKey), | 69 | id: parseInt(languageKey, 10), |
70 | label: data[languageKey] | 70 | label: data[languageKey] |
71 | }); | 71 | }) |
72 | }); | 72 | }) |
73 | }); | 73 | }) |
74 | } | 74 | } |
75 | 75 | ||
76 | getVideo(id: string): Observable<Video> { | 76 | getVideo (id: string): Observable<Video> { |
77 | return this.http.get(VideoService.BASE_VIDEO_URL + id) | 77 | return this.http.get(VideoService.BASE_VIDEO_URL + id) |
78 | .map(this.restExtractor.extractDataGet) | 78 | .map(this.restExtractor.extractDataGet) |
79 | .map(video_hash => new Video(video_hash)) | 79 | .map(videoHash => new Video(videoHash)) |
80 | .catch((res) => this.restExtractor.handleError(res)); | 80 | .catch((res) => this.restExtractor.handleError(res)) |
81 | } | 81 | } |
82 | 82 | ||
83 | updateVideo(video: Video) { | 83 | updateVideo (video: Video) { |
84 | const language = video.language ? video.language : null; | 84 | const language = video.language ? video.language : null |
85 | 85 | ||
86 | const body = { | 86 | const body = { |
87 | name: video.name, | 87 | name: video.name, |
@@ -90,94 +90,94 @@ export class VideoService { | |||
90 | language, | 90 | language, |
91 | description: video.description, | 91 | description: video.description, |
92 | tags: video.tags | 92 | tags: video.tags |
93 | }; | 93 | } |
94 | 94 | ||
95 | const headers = new Headers({ 'Content-Type': 'application/json' }); | 95 | const headers = new Headers({ 'Content-Type': 'application/json' }) |
96 | const options = new RequestOptions({ headers: headers }); | 96 | const options = new RequestOptions({ headers: headers }) |
97 | 97 | ||
98 | return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body, options) | 98 | return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body, options) |
99 | .map(this.restExtractor.extractDataBool) | 99 | .map(this.restExtractor.extractDataBool) |
100 | .catch(this.restExtractor.handleError); | 100 | .catch(this.restExtractor.handleError) |
101 | } | 101 | } |
102 | 102 | ||
103 | getVideos(pagination: RestPagination, sort: SortField) { | 103 | getVideos (pagination: RestPagination, sort: SortField) { |
104 | const params = this.restService.buildRestGetParams(pagination, sort); | 104 | const params = this.restService.buildRestGetParams(pagination, sort) |
105 | 105 | ||
106 | return this.http.get(VideoService.BASE_VIDEO_URL, { search: params }) | 106 | return this.http.get(VideoService.BASE_VIDEO_URL, { search: params }) |
107 | .map(res => res.json()) | 107 | .map(res => res.json()) |
108 | .map(this.extractVideos) | 108 | .map(this.extractVideos) |
109 | .catch((res) => this.restExtractor.handleError(res)); | 109 | .catch((res) => this.restExtractor.handleError(res)) |
110 | } | 110 | } |
111 | 111 | ||
112 | removeVideo(id: string) { | 112 | removeVideo (id: string) { |
113 | return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id) | 113 | return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id) |
114 | .map(this.restExtractor.extractDataBool) | 114 | .map(this.restExtractor.extractDataBool) |
115 | .catch((res) => this.restExtractor.handleError(res)); | 115 | .catch((res) => this.restExtractor.handleError(res)) |
116 | } | 116 | } |
117 | 117 | ||
118 | searchVideos(search: Search, pagination: RestPagination, sort: SortField) { | 118 | searchVideos (search: Search, pagination: RestPagination, sort: SortField) { |
119 | const params = this.restService.buildRestGetParams(pagination, sort); | 119 | const params = this.restService.buildRestGetParams(pagination, sort) |
120 | 120 | ||
121 | if (search.field) params.set('field', search.field); | 121 | if (search.field) params.set('field', search.field) |
122 | 122 | ||
123 | return this.http.get(VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value), { search: params }) | 123 | return this.http.get(VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value), { search: params }) |
124 | .map(this.restExtractor.extractDataList) | 124 | .map(this.restExtractor.extractDataList) |
125 | .map(this.extractVideos) | 125 | .map(this.extractVideos) |
126 | .catch((res) => this.restExtractor.handleError(res)); | 126 | .catch((res) => this.restExtractor.handleError(res)) |
127 | } | 127 | } |
128 | 128 | ||
129 | reportVideo(id: string, reason: string) { | 129 | reportVideo (id: string, reason: string) { |
130 | const url = VideoService.BASE_VIDEO_URL + id + '/abuse'; | 130 | const url = VideoService.BASE_VIDEO_URL + id + '/abuse' |
131 | const body = { | 131 | const body = { |
132 | reason | 132 | reason |
133 | }; | 133 | } |
134 | 134 | ||
135 | return this.authHttp.post(url, body) | 135 | return this.authHttp.post(url, body) |
136 | .map(this.restExtractor.extractDataBool) | 136 | .map(this.restExtractor.extractDataBool) |
137 | .catch((res) => this.restExtractor.handleError(res)); | 137 | .catch((res) => this.restExtractor.handleError(res)) |
138 | } | 138 | } |
139 | 139 | ||
140 | setVideoLike(id: string) { | 140 | setVideoLike (id: string) { |
141 | return this.setVideoRate(id, 'like'); | 141 | return this.setVideoRate(id, 'like') |
142 | } | 142 | } |
143 | 143 | ||
144 | setVideoDislike(id: string) { | 144 | setVideoDislike (id: string) { |
145 | return this.setVideoRate(id, 'dislike'); | 145 | return this.setVideoRate(id, 'dislike') |
146 | } | 146 | } |
147 | 147 | ||
148 | getUserVideoRating(id: string) { | 148 | getUserVideoRating (id: string) { |
149 | const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating'; | 149 | const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating' |
150 | 150 | ||
151 | return this.authHttp.get(url) | 151 | return this.authHttp.get(url) |
152 | .map(this.restExtractor.extractDataGet) | 152 | .map(this.restExtractor.extractDataGet) |
153 | .catch((res) => this.restExtractor.handleError(res)); | 153 | .catch((res) => this.restExtractor.handleError(res)) |
154 | } | 154 | } |
155 | 155 | ||
156 | blacklistVideo(id: string) { | 156 | blacklistVideo (id: string) { |
157 | return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {}) | 157 | return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {}) |
158 | .map(this.restExtractor.extractDataBool) | 158 | .map(this.restExtractor.extractDataBool) |
159 | .catch((res) => this.restExtractor.handleError(res)); | 159 | .catch((res) => this.restExtractor.handleError(res)) |
160 | } | 160 | } |
161 | 161 | ||
162 | private setVideoRate(id: string, rateType: RateType) { | 162 | private setVideoRate (id: string, rateType: RateType) { |
163 | const url = VideoService.BASE_VIDEO_URL + id + '/rate'; | 163 | const url = VideoService.BASE_VIDEO_URL + id + '/rate' |
164 | const body = { | 164 | const body = { |
165 | rating: rateType | 165 | rating: rateType |
166 | }; | 166 | } |
167 | 167 | ||
168 | return this.authHttp.put(url, body) | 168 | return this.authHttp.put(url, body) |
169 | .map(this.restExtractor.extractDataBool) | 169 | .map(this.restExtractor.extractDataBool) |
170 | .catch((res) => this.restExtractor.handleError(res)); | 170 | .catch((res) => this.restExtractor.handleError(res)) |
171 | } | 171 | } |
172 | 172 | ||
173 | private extractVideos(result: ResultList) { | 173 | private extractVideos (result: ResultList) { |
174 | const videosJson = result.data; | 174 | const videosJson = result.data |
175 | const totalVideos = result.total; | 175 | const totalVideos = result.total |
176 | const videos = []; | 176 | const videos = [] |
177 | for (const videoJson of videosJson) { | 177 | for (const videoJson of videosJson) { |
178 | videos.push(new Video(videoJson)); | 178 | videos.push(new Video(videoJson)) |
179 | } | 179 | } |
180 | 180 | ||
181 | return { videos, totalVideos }; | 181 | return { videos, totalVideos } |
182 | } | 182 | } |
183 | } | 183 | } |
diff --git a/client/src/app/videos/video-edit/index.ts b/client/src/app/videos/video-edit/index.ts index 5ce4fb9b1..3b4a9cb87 100644 --- a/client/src/app/videos/video-edit/index.ts +++ b/client/src/app/videos/video-edit/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './video-add.component'; | 1 | export * from './video-add.component' |
2 | export * from './video-update.component'; | 2 | export * from './video-update.component' |
diff --git a/client/src/app/videos/video-edit/video-add.component.ts b/client/src/app/videos/video-edit/video-add.component.ts index e5eb9a9f4..0653f5ac4 100644 --- a/client/src/app/videos/video-edit/video-add.component.ts +++ b/client/src/app/videos/video-edit/video-add.component.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { Component, ElementRef, OnInit } from '@angular/core'; | 1 | import { Component, ElementRef, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload'; | 5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload' |
6 | import { NotificationsService } from 'angular2-notifications'; | 6 | import { NotificationsService } from 'angular2-notifications' |
7 | 7 | ||
8 | import { AuthService } from '../../core'; | 8 | import { AuthService } from '../../core' |
9 | import { | 9 | import { |
10 | FormReactive, | 10 | FormReactive, |
11 | VIDEO_NAME, | 11 | VIDEO_NAME, |
@@ -14,8 +14,8 @@ import { | |||
14 | VIDEO_LANGUAGE, | 14 | VIDEO_LANGUAGE, |
15 | VIDEO_DESCRIPTION, | 15 | VIDEO_DESCRIPTION, |
16 | VIDEO_TAGS | 16 | VIDEO_TAGS |
17 | } from '../../shared'; | 17 | } from '../../shared' |
18 | import { VideoService } from '../shared'; | 18 | import { VideoService } from '../shared' |
19 | 19 | ||
20 | @Component({ | 20 | @Component({ |
21 | selector: 'my-videos-add', | 21 | selector: 'my-videos-add', |
@@ -24,36 +24,36 @@ import { VideoService } from '../shared'; | |||
24 | }) | 24 | }) |
25 | 25 | ||
26 | export class VideoAddComponent extends FormReactive implements OnInit { | 26 | export class VideoAddComponent extends FormReactive implements OnInit { |
27 | tags: string[] = []; | 27 | tags: string[] = [] |
28 | uploader: FileUploader; | 28 | uploader: FileUploader |
29 | videoCategories = []; | 29 | videoCategories = [] |
30 | videoLicences = []; | 30 | videoLicences = [] |
31 | videoLanguages = []; | 31 | videoLanguages = [] |
32 | 32 | ||
33 | tagValidators = VIDEO_TAGS.VALIDATORS; | 33 | tagValidators = VIDEO_TAGS.VALIDATORS |
34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES; | 34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES |
35 | 35 | ||
36 | error: string = null; | 36 | error: string = null |
37 | form: FormGroup; | 37 | form: FormGroup |
38 | formErrors = { | 38 | formErrors = { |
39 | name: '', | 39 | name: '', |
40 | category: '', | 40 | category: '', |
41 | licence: '', | 41 | licence: '', |
42 | language: '', | 42 | language: '', |
43 | description: '' | 43 | description: '' |
44 | }; | 44 | } |
45 | validationMessages = { | 45 | validationMessages = { |
46 | name: VIDEO_NAME.MESSAGES, | 46 | name: VIDEO_NAME.MESSAGES, |
47 | category: VIDEO_CATEGORY.MESSAGES, | 47 | category: VIDEO_CATEGORY.MESSAGES, |
48 | licence: VIDEO_LICENCE.MESSAGES, | 48 | licence: VIDEO_LICENCE.MESSAGES, |
49 | language: VIDEO_LANGUAGE.MESSAGES, | 49 | language: VIDEO_LANGUAGE.MESSAGES, |
50 | description: VIDEO_DESCRIPTION.MESSAGES | 50 | description: VIDEO_DESCRIPTION.MESSAGES |
51 | }; | 51 | } |
52 | 52 | ||
53 | // Special error messages | 53 | // Special error messages |
54 | fileError = ''; | 54 | fileError = '' |
55 | 55 | ||
56 | constructor( | 56 | constructor ( |
57 | private authService: AuthService, | 57 | private authService: AuthService, |
58 | private elementRef: ElementRef, | 58 | private elementRef: ElementRef, |
59 | private formBuilder: FormBuilder, | 59 | private formBuilder: FormBuilder, |
@@ -61,18 +61,18 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
61 | private notificationsService: NotificationsService, | 61 | private notificationsService: NotificationsService, |
62 | private videoService: VideoService | 62 | private videoService: VideoService |
63 | ) { | 63 | ) { |
64 | super(); | 64 | super() |
65 | } | 65 | } |
66 | 66 | ||
67 | get filename() { | 67 | get filename () { |
68 | if (this.uploader.queue.length === 0) { | 68 | if (this.uploader.queue.length === 0) { |
69 | return null; | 69 | return null |
70 | } | 70 | } |
71 | 71 | ||
72 | return this.uploader.queue[0].file.name; | 72 | return this.uploader.queue[0].file.name |
73 | } | 73 | } |
74 | 74 | ||
75 | buildForm() { | 75 | buildForm () { |
76 | this.form = this.formBuilder.group({ | 76 | this.form = this.formBuilder.group({ |
77 | name: [ '', VIDEO_NAME.VALIDATORS ], | 77 | name: [ '', VIDEO_NAME.VALIDATORS ], |
78 | nsfw: [ false ], | 78 | nsfw: [ false ], |
@@ -81,115 +81,106 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
81 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], | 81 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], |
82 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], | 82 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], |
83 | tags: [ ''] | 83 | tags: [ ''] |
84 | }); | 84 | }) |
85 | 85 | ||
86 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 86 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
87 | } | 87 | } |
88 | 88 | ||
89 | ngOnInit() { | 89 | ngOnInit () { |
90 | this.videoCategories = this.videoService.videoCategories; | 90 | this.videoCategories = this.videoService.videoCategories |
91 | this.videoLicences = this.videoService.videoLicences; | 91 | this.videoLicences = this.videoService.videoLicences |
92 | this.videoLanguages = this.videoService.videoLanguages; | 92 | this.videoLanguages = this.videoService.videoLanguages |
93 | 93 | ||
94 | this.uploader = new FileUploader({ | 94 | this.uploader = new FileUploader({ |
95 | authToken: this.authService.getRequestHeaderValue(), | 95 | authToken: this.authService.getRequestHeaderValue(), |
96 | queueLimit: 1, | 96 | queueLimit: 1, |
97 | url: API_URL + '/api/v1/videos', | 97 | url: API_URL + '/api/v1/videos', |
98 | removeAfterUpload: true | 98 | removeAfterUpload: true |
99 | }); | 99 | }) |
100 | 100 | ||
101 | this.uploader.onBuildItemForm = (item, form) => { | 101 | this.uploader.onBuildItemForm = (item, form) => { |
102 | const name = this.form.value['name']; | 102 | const name = this.form.value['name'] |
103 | const nsfw = this.form.value['nsfw']; | 103 | const nsfw = this.form.value['nsfw'] |
104 | const category = this.form.value['category']; | 104 | const category = this.form.value['category'] |
105 | const licence = this.form.value['licence']; | 105 | const licence = this.form.value['licence'] |
106 | const language = this.form.value['language']; | 106 | const language = this.form.value['language'] |
107 | const description = this.form.value['description']; | 107 | const description = this.form.value['description'] |
108 | const tags = this.form.value['tags']; | 108 | const tags = this.form.value['tags'] |
109 | 109 | ||
110 | form.append('name', name); | 110 | form.append('name', name) |
111 | form.append('category', category); | 111 | form.append('category', category) |
112 | form.append('nsfw', nsfw); | 112 | form.append('nsfw', nsfw) |
113 | form.append('licence', licence); | 113 | form.append('licence', licence) |
114 | 114 | ||
115 | // Language is optional | 115 | // Language is optional |
116 | if (language) { | 116 | if (language) { |
117 | form.append('language', language); | 117 | form.append('language', language) |
118 | } | 118 | } |
119 | 119 | ||
120 | form.append('description', description); | 120 | form.append('description', description) |
121 | 121 | ||
122 | for (let i = 0; i < tags.length; i++) { | 122 | for (let i = 0; i < tags.length; i++) { |
123 | form.append(`tags[${i}]`, tags[i]); | 123 | form.append(`tags[${i}]`, tags[i]) |
124 | } | 124 | } |
125 | }; | 125 | } |
126 | 126 | ||
127 | this.buildForm(); | 127 | this.buildForm() |
128 | } | 128 | } |
129 | 129 | ||
130 | checkForm() { | 130 | checkForm () { |
131 | this.forceCheck(); | 131 | this.forceCheck() |
132 | 132 | ||
133 | if (this.filename === null) { | 133 | if (this.filename === null) { |
134 | this.fileError = 'You did not add a file.'; | 134 | this.fileError = 'You did not add a file.' |
135 | } | 135 | } |
136 | 136 | ||
137 | return this.form.valid === true && this.fileError === ''; | 137 | return this.form.valid === true && this.fileError === '' |
138 | } | 138 | } |
139 | 139 | ||
140 | fileChanged() { | 140 | fileChanged () { |
141 | this.fileError = ''; | 141 | this.fileError = '' |
142 | } | 142 | } |
143 | 143 | ||
144 | removeFile() { | 144 | removeFile () { |
145 | this.uploader.clearQueue(); | 145 | this.uploader.clearQueue() |
146 | } | 146 | } |
147 | 147 | ||
148 | upload() { | 148 | upload () { |
149 | if (this.checkForm() === false) { | 149 | if (this.checkForm() === false) { |
150 | return; | 150 | return |
151 | } | 151 | } |
152 | 152 | ||
153 | const item = this.uploader.queue[0]; | 153 | const item = this.uploader.queue[0] |
154 | // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 | 154 | // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 |
155 | item.alias = 'videofile'; | 155 | item.alias = 'videofile' |
156 | |||
157 | // FIXME: remove | ||
158 | // Run detection change for progress bar | ||
159 | const interval = setInterval(() => { ; }, 250); | ||
160 | 156 | ||
161 | item.onSuccess = () => { | 157 | item.onSuccess = () => { |
162 | clearInterval(interval); | 158 | console.log('Video uploaded.') |
163 | 159 | this.notificationsService.success('Success', 'Video uploaded.') | |
164 | console.log('Video uploaded.'); | ||
165 | this.notificationsService.success('Success', 'Video uploaded.'); | ||
166 | |||
167 | 160 | ||
168 | // Print all the videos once it's finished | 161 | // Print all the videos once it's finished |
169 | this.router.navigate(['/videos/list']); | 162 | this.router.navigate(['/videos/list']) |
170 | }; | 163 | } |
171 | 164 | ||
172 | item.onError = (response: string, status: number) => { | 165 | item.onError = (response: string, status: number) => { |
173 | clearInterval(interval); | ||
174 | |||
175 | // We need to handle manually these cases beceause we use the FileUpload component | 166 | // We need to handle manually these cases beceause we use the FileUpload component |
176 | if (status === 400) { | 167 | if (status === 400) { |
177 | this.error = response; | 168 | this.error = response |
178 | } else if (status === 401) { | 169 | } else if (status === 401) { |
179 | this.error = 'Access token was expired, refreshing token...'; | 170 | this.error = 'Access token was expired, refreshing token...' |
180 | this.authService.refreshAccessToken().subscribe( | 171 | this.authService.refreshAccessToken().subscribe( |
181 | () => { | 172 | () => { |
182 | // Update the uploader request header | 173 | // Update the uploader request header |
183 | this.uploader.authToken = this.authService.getRequestHeaderValue(); | 174 | this.uploader.authToken = this.authService.getRequestHeaderValue() |
184 | this.error += ' access token refreshed. Please retry your request.'; | 175 | this.error += ' access token refreshed. Please retry your request.' |
185 | } | 176 | } |
186 | ); | 177 | ) |
187 | } else { | 178 | } else { |
188 | this.error = 'Unknow error'; | 179 | this.error = 'Unknow error' |
189 | console.error(this.error); | 180 | console.error(this.error) |
190 | } | 181 | } |
191 | }; | 182 | } |
192 | 183 | ||
193 | this.uploader.uploadAll(); | 184 | this.uploader.uploadAll() |
194 | } | 185 | } |
195 | } | 186 | } |
diff --git a/client/src/app/videos/video-edit/video-update.component.ts b/client/src/app/videos/video-edit/video-update.component.ts index 933132cc0..9ee7ca6a8 100644 --- a/client/src/app/videos/video-edit/video-update.component.ts +++ b/client/src/app/videos/video-edit/video-update.component.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { Component, ElementRef, OnInit } from '@angular/core'; | 1 | import { Component, ElementRef, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { ActivatedRoute, Router } from '@angular/router'; | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | 4 | ||
5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload'; | 5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload' |
6 | import { NotificationsService } from 'angular2-notifications'; | 6 | import { NotificationsService } from 'angular2-notifications' |
7 | 7 | ||
8 | import { AuthService } from '../../core'; | 8 | import { AuthService } from '../../core' |
9 | import { | 9 | import { |
10 | FormReactive, | 10 | FormReactive, |
11 | VIDEO_NAME, | 11 | VIDEO_NAME, |
@@ -14,8 +14,8 @@ import { | |||
14 | VIDEO_LANGUAGE, | 14 | VIDEO_LANGUAGE, |
15 | VIDEO_DESCRIPTION, | 15 | VIDEO_DESCRIPTION, |
16 | VIDEO_TAGS | 16 | VIDEO_TAGS |
17 | } from '../../shared'; | 17 | } from '../../shared' |
18 | import { Video, VideoService } from '../shared'; | 18 | import { Video, VideoService } from '../shared' |
19 | 19 | ||
20 | @Component({ | 20 | @Component({ |
21 | selector: 'my-videos-update', | 21 | selector: 'my-videos-update', |
@@ -24,35 +24,35 @@ import { Video, VideoService } from '../shared'; | |||
24 | }) | 24 | }) |
25 | 25 | ||
26 | export class VideoUpdateComponent extends FormReactive implements OnInit { | 26 | export class VideoUpdateComponent extends FormReactive implements OnInit { |
27 | tags: string[] = []; | 27 | tags: string[] = [] |
28 | videoCategories = []; | 28 | videoCategories = [] |
29 | videoLicences = []; | 29 | videoLicences = [] |
30 | videoLanguages = []; | 30 | videoLanguages = [] |
31 | video: Video; | 31 | video: Video |
32 | 32 | ||
33 | tagValidators = VIDEO_TAGS.VALIDATORS; | 33 | tagValidators = VIDEO_TAGS.VALIDATORS |
34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES; | 34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES |
35 | 35 | ||
36 | error: string = null; | 36 | error: string = null |
37 | form: FormGroup; | 37 | form: FormGroup |
38 | formErrors = { | 38 | formErrors = { |
39 | name: '', | 39 | name: '', |
40 | category: '', | 40 | category: '', |
41 | licence: '', | 41 | licence: '', |
42 | language: '', | 42 | language: '', |
43 | description: '' | 43 | description: '' |
44 | }; | 44 | } |
45 | validationMessages = { | 45 | validationMessages = { |
46 | name: VIDEO_NAME.MESSAGES, | 46 | name: VIDEO_NAME.MESSAGES, |
47 | category: VIDEO_CATEGORY.MESSAGES, | 47 | category: VIDEO_CATEGORY.MESSAGES, |
48 | licence: VIDEO_LICENCE.MESSAGES, | 48 | licence: VIDEO_LICENCE.MESSAGES, |
49 | language: VIDEO_LANGUAGE.MESSAGES, | 49 | language: VIDEO_LANGUAGE.MESSAGES, |
50 | description: VIDEO_DESCRIPTION.MESSAGES | 50 | description: VIDEO_DESCRIPTION.MESSAGES |
51 | }; | 51 | } |
52 | 52 | ||
53 | fileError = ''; | 53 | fileError = '' |
54 | 54 | ||
55 | constructor( | 55 | constructor ( |
56 | private authService: AuthService, | 56 | private authService: AuthService, |
57 | private elementRef: ElementRef, | 57 | private elementRef: ElementRef, |
58 | private formBuilder: FormBuilder, | 58 | private formBuilder: FormBuilder, |
@@ -61,10 +61,10 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
61 | private notificationsService: NotificationsService, | 61 | private notificationsService: NotificationsService, |
62 | private videoService: VideoService | 62 | private videoService: VideoService |
63 | ) { | 63 | ) { |
64 | super(); | 64 | super() |
65 | } | 65 | } |
66 | 66 | ||
67 | buildForm() { | 67 | buildForm () { |
68 | this.form = this.formBuilder.group({ | 68 | this.form = this.formBuilder.group({ |
69 | name: [ '', VIDEO_NAME.VALIDATORS ], | 69 | name: [ '', VIDEO_NAME.VALIDATORS ], |
70 | nsfw: [ false ], | 70 | nsfw: [ false ], |
@@ -73,60 +73,63 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
73 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], | 73 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], |
74 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], | 74 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], |
75 | tags: [ '' ] | 75 | tags: [ '' ] |
76 | }); | 76 | }) |
77 | 77 | ||
78 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 78 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
79 | } | 79 | } |
80 | 80 | ||
81 | ngOnInit() { | 81 | ngOnInit () { |
82 | this.buildForm(); | 82 | this.buildForm() |
83 | 83 | ||
84 | this.videoCategories = this.videoService.videoCategories; | 84 | this.videoCategories = this.videoService.videoCategories |
85 | this.videoLicences = this.videoService.videoLicences; | 85 | this.videoLicences = this.videoService.videoLicences |
86 | this.videoLanguages = this.videoService.videoLanguages; | 86 | this.videoLanguages = this.videoService.videoLanguages |
87 | 87 | ||
88 | const id = this.route.snapshot.params['id']; | 88 | const id = this.route.snapshot.params['id'] |
89 | this.videoService.getVideo(id) | 89 | this.videoService.getVideo(id) |
90 | .subscribe( | 90 | .subscribe( |
91 | video => { | 91 | video => { |
92 | this.video = video; | 92 | this.video = video |
93 | 93 | ||
94 | this.hydrateFormFromVideo(); | 94 | this.hydrateFormFromVideo() |
95 | }, | 95 | }, |
96 | 96 | ||
97 | err => this.error = 'Cannot fetch video.' | 97 | err => { |
98 | ); | 98 | console.error(err) |
99 | this.error = 'Cannot fetch video.' | ||
100 | } | ||
101 | ) | ||
99 | } | 102 | } |
100 | 103 | ||
101 | checkForm() { | 104 | checkForm () { |
102 | this.forceCheck(); | 105 | this.forceCheck() |
103 | 106 | ||
104 | return this.form.valid; | 107 | return this.form.valid |
105 | } | 108 | } |
106 | 109 | ||
107 | update() { | 110 | update () { |
108 | if (this.checkForm() === false) { | 111 | if (this.checkForm() === false) { |
109 | return; | 112 | return |
110 | } | 113 | } |
111 | 114 | ||
112 | this.video.patch(this.form.value); | 115 | this.video.patch(this.form.value) |
113 | 116 | ||
114 | this.videoService.updateVideo(this.video) | 117 | this.videoService.updateVideo(this.video) |
115 | .subscribe( | 118 | .subscribe( |
116 | () => { | 119 | () => { |
117 | this.notificationsService.success('Success', 'Video updated.'); | 120 | this.notificationsService.success('Success', 'Video updated.') |
118 | this.router.navigate([ '/videos/watch', this.video.id ]); | 121 | this.router.navigate([ '/videos/watch', this.video.id ]) |
119 | }, | 122 | }, |
120 | 123 | ||
121 | err => { | 124 | err => { |
122 | this.error = 'Cannot update the video.'; | 125 | this.error = 'Cannot update the video.' |
123 | console.error(err); | 126 | console.error(err) |
124 | } | 127 | } |
125 | ); | 128 | ) |
126 | 129 | ||
127 | } | 130 | } |
128 | 131 | ||
129 | private hydrateFormFromVideo() { | 132 | private hydrateFormFromVideo () { |
130 | this.form.patchValue(this.video.toJSON()); | 133 | this.form.patchValue(this.video.toJSON()) |
131 | } | 134 | } |
132 | } | 135 | } |
diff --git a/client/src/app/videos/video-list/index.ts b/client/src/app/videos/video-list/index.ts index 71d3b78e6..a490e6bb5 100644 --- a/client/src/app/videos/video-list/index.ts +++ b/client/src/app/videos/video-list/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './loader.component'; | 1 | export * from './loader.component' |
2 | export * from './video-list.component'; | 2 | export * from './video-list.component' |
3 | export * from './video-miniature.component'; | 3 | export * from './video-miniature.component' |
4 | export * from './video-sort.component'; | 4 | export * from './video-sort.component' |
diff --git a/client/src/app/videos/video-list/loader.component.ts b/client/src/app/videos/video-list/loader.component.ts index e72d2f3f3..e5780e0fa 100644 --- a/client/src/app/videos/video-list/loader.component.ts +++ b/client/src/app/videos/video-list/loader.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component, Input } from '@angular/core'; | 1 | import { Component, Input } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | selector: 'my-loader', | 4 | selector: 'my-loader', |
@@ -7,5 +7,5 @@ import { Component, Input } from '@angular/core'; | |||
7 | }) | 7 | }) |
8 | 8 | ||
9 | export class LoaderComponent { | 9 | export class LoaderComponent { |
10 | @Input() loading: boolean; | 10 | @Input() loading: boolean |
11 | } | 11 | } |
diff --git a/client/src/app/videos/video-list/video-list.component.html b/client/src/app/videos/video-list/video-list.component.html index f80592279..680fba3f5 100644 --- a/client/src/app/videos/video-list/video-list.component.html +++ b/client/src/app/videos/video-list/video-list.component.html | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | <my-video-miniature | 18 | <my-video-miniature |
19 | class="ng-animate" | 19 | class="ng-animate" |
20 | *ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort" (removed)="onRemoved(video)" | 20 | *ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort" |
21 | > | 21 | > |
22 | </my-video-miniature> | 22 | </my-video-miniature> |
23 | </div> | 23 | </div> |
diff --git a/client/src/app/videos/video-list/video-list.component.ts b/client/src/app/videos/video-list/video-list.component.ts index 16a40bdc4..0c36e5b08 100644 --- a/client/src/app/videos/video-list/video-list.component.ts +++ b/client/src/app/videos/video-list/video-list.component.ts | |||
@@ -1,17 +1,17 @@ | |||
1 | import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; | 1 | import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router'; | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { BehaviorSubject } from 'rxjs/BehaviorSubject'; | 3 | import { BehaviorSubject } from 'rxjs/BehaviorSubject' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { | 7 | import { |
8 | SortField, | 8 | SortField, |
9 | Video, | 9 | Video, |
10 | VideoService | 10 | VideoService |
11 | } from '../shared'; | 11 | } from '../shared' |
12 | import { AuthService, AuthUser } from '../../core'; | 12 | import { AuthService, AuthUser } from '../../core' |
13 | import { RestPagination, Search, SearchField } from '../../shared'; | 13 | import { RestPagination, Search, SearchField } from '../../shared' |
14 | import { SearchService } from '../../shared'; | 14 | import { SearchService } from '../../shared' |
15 | 15 | ||
16 | @Component({ | 16 | @Component({ |
17 | selector: 'my-videos-list', | 17 | selector: 'my-videos-list', |
@@ -19,21 +19,21 @@ import { SearchService } from '../../shared'; | |||
19 | templateUrl: './video-list.component.html' | 19 | templateUrl: './video-list.component.html' |
20 | }) | 20 | }) |
21 | export class VideoListComponent implements OnInit, OnDestroy { | 21 | export class VideoListComponent implements OnInit, OnDestroy { |
22 | loading: BehaviorSubject<boolean> = new BehaviorSubject(false); | 22 | loading: BehaviorSubject<boolean> = new BehaviorSubject(false) |
23 | pagination: RestPagination = { | 23 | pagination: RestPagination = { |
24 | currentPage: 1, | 24 | currentPage: 1, |
25 | itemsPerPage: 25, | 25 | itemsPerPage: 25, |
26 | totalItems: null | 26 | totalItems: null |
27 | }; | 27 | } |
28 | sort: SortField; | 28 | sort: SortField |
29 | user: AuthUser = null; | 29 | user: AuthUser = null |
30 | videos: Video[] = []; | 30 | videos: Video[] = [] |
31 | 31 | ||
32 | private search: Search; | 32 | private search: Search |
33 | private subActivatedRoute: any; | 33 | private subActivatedRoute: any |
34 | private subSearch: any; | 34 | private subSearch: any |
35 | 35 | ||
36 | constructor( | 36 | constructor ( |
37 | private notificationsService: NotificationsService, | 37 | private notificationsService: NotificationsService, |
38 | private authService: AuthService, | 38 | private authService: AuthService, |
39 | private changeDetector: ChangeDetectorRef, | 39 | private changeDetector: ChangeDetectorRef, |
@@ -43,114 +43,114 @@ export class VideoListComponent implements OnInit, OnDestroy { | |||
43 | private searchService: SearchService | 43 | private searchService: SearchService |
44 | ) {} | 44 | ) {} |
45 | 45 | ||
46 | ngOnInit() { | 46 | ngOnInit () { |
47 | if (this.authService.isLoggedIn()) { | 47 | if (this.authService.isLoggedIn()) { |
48 | this.user = AuthUser.load(); | 48 | this.user = AuthUser.load() |
49 | } | 49 | } |
50 | 50 | ||
51 | // Subscribe to route changes | 51 | // Subscribe to route changes |
52 | this.subActivatedRoute = this.route.params.subscribe(routeParams => { | 52 | this.subActivatedRoute = this.route.params.subscribe(routeParams => { |
53 | this.loadRouteParams(routeParams); | 53 | this.loadRouteParams(routeParams) |
54 | 54 | ||
55 | // Update the search service component | 55 | // Update the search service component |
56 | this.searchService.updateSearch.next(this.search); | 56 | this.searchService.updateSearch.next(this.search) |
57 | this.getVideos(); | 57 | this.getVideos() |
58 | }); | 58 | }) |
59 | 59 | ||
60 | // Subscribe to search changes | 60 | // Subscribe to search changes |
61 | this.subSearch = this.searchService.searchUpdated.subscribe(search => { | 61 | this.subSearch = this.searchService.searchUpdated.subscribe(search => { |
62 | this.search = search; | 62 | this.search = search |
63 | // Reset pagination | 63 | // Reset pagination |
64 | this.pagination.currentPage = 1; | 64 | this.pagination.currentPage = 1 |
65 | 65 | ||
66 | this.navigateToNewParams(); | 66 | this.navigateToNewParams() |
67 | }); | 67 | }) |
68 | } | 68 | } |
69 | 69 | ||
70 | ngOnDestroy() { | 70 | ngOnDestroy () { |
71 | this.subActivatedRoute.unsubscribe(); | 71 | this.subActivatedRoute.unsubscribe() |
72 | this.subSearch.unsubscribe(); | 72 | this.subSearch.unsubscribe() |
73 | } | 73 | } |
74 | 74 | ||
75 | getVideos() { | 75 | getVideos () { |
76 | this.loading.next(true); | 76 | this.loading.next(true) |
77 | this.videos = []; | 77 | this.videos = [] |
78 | 78 | ||
79 | let observable = null; | 79 | let observable = null |
80 | if (this.search.value) { | 80 | if (this.search.value) { |
81 | observable = this.videoService.searchVideos(this.search, this.pagination, this.sort); | 81 | observable = this.videoService.searchVideos(this.search, this.pagination, this.sort) |
82 | } else { | 82 | } else { |
83 | observable = this.videoService.getVideos(this.pagination, this.sort); | 83 | observable = this.videoService.getVideos(this.pagination, this.sort) |
84 | } | 84 | } |
85 | 85 | ||
86 | observable.subscribe( | 86 | observable.subscribe( |
87 | ({ videos, totalVideos }) => { | 87 | ({ videos, totalVideos }) => { |
88 | this.videos = videos; | 88 | this.videos = videos |
89 | this.pagination.totalItems = totalVideos; | 89 | this.pagination.totalItems = totalVideos |
90 | 90 | ||
91 | this.loading.next(false); | 91 | this.loading.next(false) |
92 | }, | 92 | }, |
93 | error => this.notificationsService.error('Error', error.text) | 93 | error => this.notificationsService.error('Error', error.text) |
94 | ); | 94 | ) |
95 | } | 95 | } |
96 | 96 | ||
97 | isThereNoVideo() { | 97 | isThereNoVideo () { |
98 | return !this.loading.getValue() && this.videos.length === 0; | 98 | return !this.loading.getValue() && this.videos.length === 0 |
99 | } | 99 | } |
100 | 100 | ||
101 | onPageChanged(event: any) { | 101 | onPageChanged (event: any) { |
102 | // Be sure the current page is set | 102 | // Be sure the current page is set |
103 | this.pagination.currentPage = event.page; | 103 | this.pagination.currentPage = event.page |
104 | 104 | ||
105 | this.navigateToNewParams(); | 105 | this.navigateToNewParams() |
106 | } | 106 | } |
107 | 107 | ||
108 | onSort(sort: SortField) { | 108 | onSort (sort: SortField) { |
109 | this.sort = sort; | 109 | this.sort = sort |
110 | 110 | ||
111 | this.navigateToNewParams(); | 111 | this.navigateToNewParams() |
112 | } | 112 | } |
113 | 113 | ||
114 | private buildRouteParams() { | 114 | private buildRouteParams () { |
115 | // There is always a sort and a current page | 115 | // There is always a sort and a current page |
116 | const params: any = { | 116 | const params: any = { |
117 | sort: this.sort, | 117 | sort: this.sort, |
118 | page: this.pagination.currentPage | 118 | page: this.pagination.currentPage |
119 | }; | 119 | } |
120 | 120 | ||
121 | // Maybe there is a search | 121 | // Maybe there is a search |
122 | if (this.search.value) { | 122 | if (this.search.value) { |
123 | params.field = this.search.field; | 123 | params.field = this.search.field |
124 | params.search = this.search.value; | 124 | params.search = this.search.value |
125 | } | 125 | } |
126 | 126 | ||
127 | return params; | 127 | return params |
128 | } | 128 | } |
129 | 129 | ||
130 | private loadRouteParams(routeParams) { | 130 | private loadRouteParams (routeParams) { |
131 | if (routeParams['search'] !== undefined) { | 131 | if (routeParams['search'] !== undefined) { |
132 | this.search = { | 132 | this.search = { |
133 | value: routeParams['search'], | 133 | value: routeParams['search'], |
134 | field: <SearchField>routeParams['field'] | 134 | field: routeParams['field'] as SearchField |
135 | }; | 135 | } |
136 | } else { | 136 | } else { |
137 | this.search = { | 137 | this.search = { |
138 | value: '', | 138 | value: '', |
139 | field: 'name' | 139 | field: 'name' |
140 | }; | 140 | } |
141 | } | 141 | } |
142 | 142 | ||
143 | this.sort = <SortField>routeParams['sort'] || '-createdAt'; | 143 | this.sort = routeParams['sort'] as SortField || '-createdAt' |
144 | 144 | ||
145 | if (routeParams['page'] !== undefined) { | 145 | if (routeParams['page'] !== undefined) { |
146 | this.pagination.currentPage = parseInt(routeParams['page']); | 146 | this.pagination.currentPage = parseInt(routeParams['page'], 10) |
147 | } else { | 147 | } else { |
148 | this.pagination.currentPage = 1; | 148 | this.pagination.currentPage = 1 |
149 | } | 149 | } |
150 | } | 150 | } |
151 | 151 | ||
152 | private navigateToNewParams() { | 152 | private navigateToNewParams () { |
153 | const routeParams = this.buildRouteParams(); | 153 | const routeParams = this.buildRouteParams() |
154 | this.router.navigate(['/videos/list', routeParams]); | 154 | this.router.navigate(['/videos/list', routeParams]) |
155 | } | 155 | } |
156 | } | 156 | } |
diff --git a/client/src/app/videos/video-list/video-miniature.component.ts b/client/src/app/videos/video-list/video-miniature.component.ts index 28601ca7f..1cfeacf36 100644 --- a/client/src/app/videos/video-list/video-miniature.component.ts +++ b/client/src/app/videos/video-list/video-miniature.component.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; | 1 | import { Component, Input, Output, EventEmitter } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications'; | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | 4 | ||
5 | import { ConfirmService, ConfigService } from '../../core'; | 5 | import { ConfirmService, ConfigService } from '../../core' |
6 | import { SortField, Video, VideoService } from '../shared'; | 6 | import { SortField, Video, VideoService } from '../shared' |
7 | import { User } from '../../shared'; | 7 | import { User } from '../../shared' |
8 | 8 | ||
9 | @Component({ | 9 | @Component({ |
10 | selector: 'my-video-miniature', | 10 | selector: 'my-video-miniature', |
@@ -13,25 +13,26 @@ import { User } from '../../shared'; | |||
13 | }) | 13 | }) |
14 | 14 | ||
15 | export class VideoMiniatureComponent { | 15 | export class VideoMiniatureComponent { |
16 | @Input() currentSort: SortField; | 16 | @Input() currentSort: SortField |
17 | @Input() user: User; | 17 | @Input() user: User |
18 | @Input() video: Video; | 18 | @Input() video: Video |
19 | 19 | ||
20 | constructor( | 20 | constructor ( |
21 | private notificationsService: NotificationsService, | 21 | private notificationsService: NotificationsService, |
22 | private confirmService: ConfirmService, | 22 | private confirmService: ConfirmService, |
23 | private configService: ConfigService, | 23 | private configService: ConfigService, |
24 | private videoService: VideoService | 24 | private videoService: VideoService |
25 | ) {} | 25 | ) {} |
26 | 26 | ||
27 | getVideoName() { | 27 | getVideoName () { |
28 | if (this.isVideoNSFWForThisUser()) | 28 | if (this.isVideoNSFWForThisUser()) { |
29 | return 'NSFW'; | 29 | return 'NSFW' |
30 | } | ||
30 | 31 | ||
31 | return this.video.name; | 32 | return this.video.name |
32 | } | 33 | } |
33 | 34 | ||
34 | isVideoNSFWForThisUser() { | 35 | isVideoNSFWForThisUser () { |
35 | return this.video.isVideoNSFWForUser(this.user); | 36 | return this.video.isVideoNSFWForUser(this.user) |
36 | } | 37 | } |
37 | } | 38 | } |
diff --git a/client/src/app/videos/video-list/video-sort.component.ts b/client/src/app/videos/video-list/video-sort.component.ts index 20979a395..64916bf16 100644 --- a/client/src/app/videos/video-list/video-sort.component.ts +++ b/client/src/app/videos/video-list/video-sort.component.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Component, EventEmitter, Input, Output } from '@angular/core'; | 1 | import { Component, EventEmitter, Input, Output } from '@angular/core' |
2 | 2 | ||
3 | import { SortField } from '../shared'; | 3 | import { SortField } from '../shared' |
4 | 4 | ||
5 | @Component({ | 5 | @Component({ |
6 | selector: 'my-video-sort', | 6 | selector: 'my-video-sort', |
@@ -8,9 +8,9 @@ import { SortField } from '../shared'; | |||
8 | }) | 8 | }) |
9 | 9 | ||
10 | export class VideoSortComponent { | 10 | export class VideoSortComponent { |
11 | @Output() sort = new EventEmitter<any>(); | 11 | @Output() sort = new EventEmitter<any>() |
12 | 12 | ||
13 | @Input() currentSort: SortField; | 13 | @Input() currentSort: SortField |
14 | 14 | ||
15 | sortChoices: { [ P in SortField ]: string } = { | 15 | sortChoices: { [ P in SortField ]: string } = { |
16 | 'name': 'Name - Asc', | 16 | 'name': 'Name - Asc', |
@@ -23,17 +23,17 @@ export class VideoSortComponent { | |||
23 | '-views': 'Views - Desc', | 23 | '-views': 'Views - Desc', |
24 | 'likes': 'Likes - Asc', | 24 | 'likes': 'Likes - Asc', |
25 | '-likes': 'Likes - Desc' | 25 | '-likes': 'Likes - Desc' |
26 | }; | 26 | } |
27 | 27 | ||
28 | get choiceKeys() { | 28 | get choiceKeys () { |
29 | return Object.keys(this.sortChoices); | 29 | return Object.keys(this.sortChoices) |
30 | } | 30 | } |
31 | 31 | ||
32 | getStringChoice(choiceKey: SortField) { | 32 | getStringChoice (choiceKey: SortField) { |
33 | return this.sortChoices[choiceKey]; | 33 | return this.sortChoices[choiceKey] |
34 | } | 34 | } |
35 | 35 | ||
36 | onSortChange() { | 36 | onSortChange () { |
37 | this.sort.emit(this.currentSort); | 37 | this.sort.emit(this.currentSort) |
38 | } | 38 | } |
39 | } | 39 | } |
diff --git a/client/src/app/videos/video-watch/index.ts b/client/src/app/videos/video-watch/index.ts index ed0ed2fc0..6e35262d3 100644 --- a/client/src/app/videos/video-watch/index.ts +++ b/client/src/app/videos/video-watch/index.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export * from './video-magnet.component'; | 1 | export * from './video-magnet.component' |
2 | export * from './video-share.component'; | 2 | export * from './video-share.component' |
3 | export * from './video-report.component'; | 3 | export * from './video-report.component' |
4 | export * from './video-watch.component'; | 4 | export * from './video-watch.component' |
5 | export * from './webtorrent.service'; | 5 | export * from './webtorrent.service' |
diff --git a/client/src/app/videos/video-watch/video-magnet.component.ts b/client/src/app/videos/video-watch/video-magnet.component.ts index 894fa45fc..f9432e92c 100644 --- a/client/src/app/videos/video-watch/video-magnet.component.ts +++ b/client/src/app/videos/video-watch/video-magnet.component.ts | |||
@@ -1,27 +1,27 @@ | |||
1 | import { Component, Input, ViewChild } from '@angular/core'; | 1 | import { Component, Input, ViewChild } from '@angular/core' |
2 | 2 | ||
3 | import { ModalDirective } from 'ngx-bootstrap/modal'; | 3 | import { ModalDirective } from 'ngx-bootstrap/modal' |
4 | 4 | ||
5 | import { Video } from '../shared'; | 5 | import { Video } from '../shared' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-video-magnet', | 8 | selector: 'my-video-magnet', |
9 | templateUrl: './video-magnet.component.html' | 9 | templateUrl: './video-magnet.component.html' |
10 | }) | 10 | }) |
11 | export class VideoMagnetComponent { | 11 | export class VideoMagnetComponent { |
12 | @Input() video: Video = null; | 12 | @Input() video: Video = null |
13 | 13 | ||
14 | @ViewChild('modal') modal: ModalDirective; | 14 | @ViewChild('modal') modal: ModalDirective |
15 | 15 | ||
16 | constructor() { | 16 | constructor () { |
17 | // empty | 17 | // empty |
18 | } | 18 | } |
19 | 19 | ||
20 | show() { | 20 | show () { |
21 | this.modal.show(); | 21 | this.modal.show() |
22 | } | 22 | } |
23 | 23 | ||
24 | hide() { | 24 | hide () { |
25 | this.modal.hide(); | 25 | this.modal.hide() |
26 | } | 26 | } |
27 | } | 27 | } |
diff --git a/client/src/app/videos/video-watch/video-report.component.ts b/client/src/app/videos/video-watch/video-report.component.ts index 528005b84..61213cd68 100644 --- a/client/src/app/videos/video-watch/video-report.component.ts +++ b/client/src/app/videos/video-watch/video-report.component.ts | |||
@@ -1,69 +1,69 @@ | |||
1 | import { Component, Input, OnInit, ViewChild } from '@angular/core'; | 1 | import { Component, Input, OnInit, ViewChild } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | 3 | ||
4 | import { ModalDirective } from 'ngx-bootstrap/modal'; | 4 | import { ModalDirective } from 'ngx-bootstrap/modal' |
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared'; | 7 | import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared' |
8 | import { Video, VideoService } from '../shared'; | 8 | import { Video, VideoService } from '../shared' |
9 | 9 | ||
10 | @Component({ | 10 | @Component({ |
11 | selector: 'my-video-report', | 11 | selector: 'my-video-report', |
12 | templateUrl: './video-report.component.html' | 12 | templateUrl: './video-report.component.html' |
13 | }) | 13 | }) |
14 | export class VideoReportComponent extends FormReactive implements OnInit { | 14 | export class VideoReportComponent extends FormReactive implements OnInit { |
15 | @Input() video: Video = null; | 15 | @Input() video: Video = null |
16 | 16 | ||
17 | @ViewChild('modal') modal: ModalDirective; | 17 | @ViewChild('modal') modal: ModalDirective |
18 | 18 | ||
19 | error: string = null; | 19 | error: string = null |
20 | form: FormGroup; | 20 | form: FormGroup |
21 | formErrors = { | 21 | formErrors = { |
22 | reason: '' | 22 | reason: '' |
23 | }; | 23 | } |
24 | validationMessages = { | 24 | validationMessages = { |
25 | reason: VIDEO_ABUSE_REASON.MESSAGES | 25 | reason: VIDEO_ABUSE_REASON.MESSAGES |
26 | }; | 26 | } |
27 | 27 | ||
28 | constructor( | 28 | constructor ( |
29 | private formBuilder: FormBuilder, | 29 | private formBuilder: FormBuilder, |
30 | private videoAbuseService: VideoAbuseService, | 30 | private videoAbuseService: VideoAbuseService, |
31 | private notificationsService: NotificationsService | 31 | private notificationsService: NotificationsService |
32 | ) { | 32 | ) { |
33 | super(); | 33 | super() |
34 | } | 34 | } |
35 | 35 | ||
36 | ngOnInit() { | 36 | ngOnInit () { |
37 | this.buildForm(); | 37 | this.buildForm() |
38 | } | 38 | } |
39 | 39 | ||
40 | buildForm() { | 40 | buildForm () { |
41 | this.form = this.formBuilder.group({ | 41 | this.form = this.formBuilder.group({ |
42 | reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ] | 42 | reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ] |
43 | }); | 43 | }) |
44 | 44 | ||
45 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 45 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
46 | } | 46 | } |
47 | 47 | ||
48 | show() { | 48 | show () { |
49 | this.modal.show(); | 49 | this.modal.show() |
50 | } | 50 | } |
51 | 51 | ||
52 | hide() { | 52 | hide () { |
53 | this.modal.hide(); | 53 | this.modal.hide() |
54 | } | 54 | } |
55 | 55 | ||
56 | report() { | 56 | report () { |
57 | const reason = this.form.value['reason']; | 57 | const reason = this.form.value['reason'] |
58 | 58 | ||
59 | this.videoAbuseService.reportVideo(this.video.id, reason) | 59 | this.videoAbuseService.reportVideo(this.video.id, reason) |
60 | .subscribe( | 60 | .subscribe( |
61 | () => { | 61 | () => { |
62 | this.notificationsService.success('Success', 'Video reported.'); | 62 | this.notificationsService.success('Success', 'Video reported.') |
63 | this.hide(); | 63 | this.hide() |
64 | }, | 64 | }, |
65 | 65 | ||
66 | err => this.notificationsService.error('Error', err.text) | 66 | err => this.notificationsService.error('Error', err.text) |
67 | ); | 67 | ) |
68 | } | 68 | } |
69 | } | 69 | } |
diff --git a/client/src/app/videos/video-watch/video-share.component.ts b/client/src/app/videos/video-watch/video-share.component.ts index aa921afc2..bbd25f5ef 100644 --- a/client/src/app/videos/video-watch/video-share.component.ts +++ b/client/src/app/videos/video-watch/video-share.component.ts | |||
@@ -1,42 +1,42 @@ | |||
1 | import { Component, Input, ViewChild } from '@angular/core'; | 1 | import { Component, Input, ViewChild } from '@angular/core' |
2 | 2 | ||
3 | import { ModalDirective } from 'ngx-bootstrap/modal'; | 3 | import { ModalDirective } from 'ngx-bootstrap/modal' |
4 | 4 | ||
5 | import { Video } from '../shared'; | 5 | import { Video } from '../shared' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-video-share', | 8 | selector: 'my-video-share', |
9 | templateUrl: './video-share.component.html' | 9 | templateUrl: './video-share.component.html' |
10 | }) | 10 | }) |
11 | export class VideoShareComponent { | 11 | export class VideoShareComponent { |
12 | @Input() video: Video = null; | 12 | @Input() video: Video = null |
13 | 13 | ||
14 | @ViewChild('modal') modal: ModalDirective; | 14 | @ViewChild('modal') modal: ModalDirective |
15 | 15 | ||
16 | constructor() { | 16 | constructor () { |
17 | // empty | 17 | // empty |
18 | } | 18 | } |
19 | 19 | ||
20 | show() { | 20 | show () { |
21 | this.modal.show(); | 21 | this.modal.show() |
22 | } | 22 | } |
23 | 23 | ||
24 | hide() { | 24 | hide () { |
25 | this.modal.hide(); | 25 | this.modal.hide() |
26 | } | 26 | } |
27 | 27 | ||
28 | getVideoIframeCode() { | 28 | getVideoIframeCode () { |
29 | return '<iframe width="560" height="315" ' + | 29 | return '<iframe width="560" height="315" ' + |
30 | 'src="' + window.location.origin + '/videos/embed/' + this.video.id + '" ' + | 30 | 'src="' + window.location.origin + '/videos/embed/' + this.video.id + '" ' + |
31 | 'frameborder="0" allowfullscreen>' + | 31 | 'frameborder="0" allowfullscreen>' + |
32 | '</iframe>'; | 32 | '</iframe>' |
33 | } | 33 | } |
34 | 34 | ||
35 | getVideoUrl() { | 35 | getVideoUrl () { |
36 | return window.location.href; | 36 | return window.location.href |
37 | } | 37 | } |
38 | 38 | ||
39 | notSecure() { | 39 | notSecure () { |
40 | return window.location.protocol === 'http:'; | 40 | return window.location.protocol === 'http:' |
41 | } | 41 | } |
42 | } | 42 | } |
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 bcfebf2fd..4a547f7e4 100644 --- a/client/src/app/videos/video-watch/video-watch.component.ts +++ b/client/src/app/videos/video-watch/video-watch.component.ts | |||
@@ -1,18 +1,18 @@ | |||
1 | import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'; | 1 | import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router'; | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { Observable } from 'rxjs/Observable'; | 3 | import { Observable } from 'rxjs/Observable' |
4 | import { Subscription } from 'rxjs/Subscription'; | 4 | import { Subscription } from 'rxjs/Subscription' |
5 | 5 | ||
6 | import * as videojs from 'video.js'; | 6 | import * as videojs from 'video.js' |
7 | import { MetaService } from '@nglibs/meta'; | 7 | import { MetaService } from '@nglibs/meta' |
8 | import { NotificationsService } from 'angular2-notifications'; | 8 | import { NotificationsService } from 'angular2-notifications' |
9 | 9 | ||
10 | import { AuthService, ConfirmService } from '../../core'; | 10 | import { AuthService, ConfirmService } from '../../core' |
11 | import { VideoMagnetComponent } from './video-magnet.component'; | 11 | import { VideoMagnetComponent } from './video-magnet.component' |
12 | import { VideoShareComponent } from './video-share.component'; | 12 | import { VideoShareComponent } from './video-share.component' |
13 | import { VideoReportComponent } from './video-report.component'; | 13 | import { VideoReportComponent } from './video-report.component' |
14 | import { RateType, Video, VideoService } from '../shared'; | 14 | import { RateType, Video, VideoService } from '../shared' |
15 | import { WebTorrentService } from './webtorrent.service'; | 15 | import { WebTorrentService } from './webtorrent.service' |
16 | 16 | ||
17 | @Component({ | 17 | @Component({ |
18 | selector: 'my-video-watch', | 18 | selector: 'my-video-watch', |
@@ -21,30 +21,30 @@ import { WebTorrentService } from './webtorrent.service'; | |||
21 | }) | 21 | }) |
22 | 22 | ||
23 | export class VideoWatchComponent implements OnInit, OnDestroy { | 23 | export class VideoWatchComponent implements OnInit, OnDestroy { |
24 | private static LOADTIME_TOO_LONG = 20000; | 24 | private static LOADTIME_TOO_LONG = 20000 |
25 | 25 | ||
26 | @ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent; | 26 | @ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent |
27 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent; | 27 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent |
28 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent; | 28 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent |
29 | 29 | ||
30 | downloadSpeed: number; | 30 | downloadSpeed: number |
31 | error = false; | 31 | error = false |
32 | loading = false; | 32 | loading = false |
33 | numPeers: number; | 33 | numPeers: number |
34 | player: videojs.Player; | 34 | player: videojs.Player |
35 | playerElement: Element; | 35 | playerElement: Element |
36 | uploadSpeed: number; | 36 | uploadSpeed: number |
37 | userRating: RateType = null; | 37 | userRating: RateType = null |
38 | video: Video = null; | 38 | video: Video = null |
39 | videoNotFound = false; | 39 | videoNotFound = false |
40 | 40 | ||
41 | private errorTimer: number; | 41 | private errorTimer: number |
42 | private paramsSub: Subscription; | 42 | private paramsSub: Subscription |
43 | private errorsSub: Subscription; | 43 | private errorsSub: Subscription |
44 | private warningsSub: Subscription; | 44 | private warningsSub: Subscription |
45 | private torrentInfosInterval: number; | 45 | private torrentInfosInterval: number |
46 | 46 | ||
47 | constructor( | 47 | constructor ( |
48 | private elementRef: ElementRef, | 48 | private elementRef: ElementRef, |
49 | private ngZone: NgZone, | 49 | private ngZone: NgZone, |
50 | private route: ActivatedRoute, | 50 | private route: ActivatedRoute, |
@@ -57,278 +57,281 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
57 | private notificationsService: NotificationsService | 57 | private notificationsService: NotificationsService |
58 | ) {} | 58 | ) {} |
59 | 59 | ||
60 | ngOnInit() { | 60 | ngOnInit () { |
61 | this.paramsSub = this.route.params.subscribe(routeParams => { | 61 | this.paramsSub = this.route.params.subscribe(routeParams => { |
62 | let id = routeParams['id']; | 62 | let id = routeParams['id'] |
63 | this.videoService.getVideo(id).subscribe( | 63 | this.videoService.getVideo(id).subscribe( |
64 | video => this.onVideoFetched(video), | 64 | video => this.onVideoFetched(video), |
65 | 65 | ||
66 | error => this.videoNotFound = true | 66 | error => { |
67 | ); | 67 | console.error(error) |
68 | }); | 68 | this.videoNotFound = true |
69 | } | ||
70 | ) | ||
71 | }) | ||
69 | 72 | ||
70 | this.playerElement = this.elementRef.nativeElement.querySelector('#video-container'); | 73 | this.playerElement = this.elementRef.nativeElement.querySelector('#video-container') |
71 | 74 | ||
72 | const videojsOptions = { | 75 | const videojsOptions = { |
73 | controls: true, | 76 | controls: true, |
74 | autoplay: false | 77 | autoplay: false |
75 | }; | 78 | } |
76 | 79 | ||
77 | const self = this; | 80 | const self = this |
78 | videojs(this.playerElement, videojsOptions, function () { | 81 | videojs(this.playerElement, videojsOptions, function () { |
79 | self.player = this; | 82 | self.player = this |
80 | }); | 83 | }) |
81 | 84 | ||
82 | this.errorsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.error('Error', err.message)); | 85 | this.errorsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.error('Error', err.message)) |
83 | this.warningsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.alert('Warning', err.message)); | 86 | this.warningsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.alert('Warning', err.message)) |
84 | } | 87 | } |
85 | 88 | ||
86 | ngOnDestroy() { | 89 | ngOnDestroy () { |
87 | // Remove WebTorrent stuff | 90 | // Remove WebTorrent stuff |
88 | console.log('Removing video from webtorrent.'); | 91 | console.log('Removing video from webtorrent.') |
89 | window.clearInterval(this.torrentInfosInterval); | 92 | window.clearInterval(this.torrentInfosInterval) |
90 | window.clearTimeout(this.errorTimer); | 93 | window.clearTimeout(this.errorTimer) |
91 | 94 | ||
92 | if (this.video !== null && this.webTorrentService.has(this.video.magnetUri)) { | 95 | if (this.video !== null && this.webTorrentService.has(this.video.magnetUri)) { |
93 | this.webTorrentService.remove(this.video.magnetUri); | 96 | this.webTorrentService.remove(this.video.magnetUri) |
94 | } | 97 | } |
95 | 98 | ||
96 | // Remove player | 99 | // Remove player |
97 | videojs(this.playerElement).dispose(); | 100 | videojs(this.playerElement).dispose() |
98 | 101 | ||
99 | // Unsubscribe subscriptions | 102 | // Unsubscribe subscriptions |
100 | this.paramsSub.unsubscribe(); | 103 | this.paramsSub.unsubscribe() |
101 | this.errorsSub.unsubscribe(); | 104 | this.errorsSub.unsubscribe() |
102 | this.warningsSub.unsubscribe(); | 105 | this.warningsSub.unsubscribe() |
103 | } | 106 | } |
104 | 107 | ||
105 | loadVideo() { | 108 | loadVideo () { |
106 | // Reset the error | 109 | // Reset the error |
107 | this.error = false; | 110 | this.error = false |
108 | // We are loading the video | 111 | // We are loading the video |
109 | this.loading = true; | 112 | this.loading = true |
110 | 113 | ||
111 | console.log('Adding ' + this.video.magnetUri + '.'); | 114 | console.log('Adding ' + this.video.magnetUri + '.') |
112 | 115 | ||
113 | // The callback might never return if there are network issues | 116 | // The callback might never return if there are network issues |
114 | // So we create a timer to inform the user the load is abnormally long | 117 | // So we create a timer to inform the user the load is abnormally long |
115 | this.errorTimer = window.setTimeout(() => this.loadTooLong(), VideoWatchComponent.LOADTIME_TOO_LONG); | 118 | this.errorTimer = window.setTimeout(() => this.loadTooLong(), VideoWatchComponent.LOADTIME_TOO_LONG) |
116 | 119 | ||
117 | this.webTorrentService.add(this.video.magnetUri, (torrent) => { | 120 | this.webTorrentService.add(this.video.magnetUri, (torrent) => { |
118 | // Clear the error timer | 121 | // Clear the error timer |
119 | window.clearTimeout(this.errorTimer); | 122 | window.clearTimeout(this.errorTimer) |
120 | // Maybe the error was fired by the timer, so reset it | 123 | // Maybe the error was fired by the timer, so reset it |
121 | this.error = false; | 124 | this.error = false |
122 | 125 | ||
123 | // We are not loading the video anymore | 126 | // We are not loading the video anymore |
124 | this.loading = false; | 127 | this.loading = false |
125 | 128 | ||
126 | console.log('Added ' + this.video.magnetUri + '.'); | 129 | console.log('Added ' + this.video.magnetUri + '.') |
127 | torrent.files[0].renderTo(this.playerElement, { autoplay: true }, (err) => { | 130 | torrent.files[0].renderTo(this.playerElement, { autoplay: true }, (err) => { |
128 | if (err) { | 131 | if (err) { |
129 | this.notificationsService.error('Error', 'Cannot append the file in the video element.'); | 132 | this.notificationsService.error('Error', 'Cannot append the file in the video element.') |
130 | console.error(err); | 133 | console.error(err) |
131 | } | 134 | } |
132 | }); | 135 | }) |
133 | 136 | ||
134 | this.runInProgress(torrent); | 137 | this.runInProgress(torrent) |
135 | }); | 138 | }) |
136 | } | 139 | } |
137 | 140 | ||
138 | setLike() { | 141 | setLike () { |
139 | if (this.isUserLoggedIn() === false) return; | 142 | if (this.isUserLoggedIn() === false) return |
140 | // Already liked this video | 143 | // Already liked this video |
141 | if (this.userRating === 'like') return; | 144 | if (this.userRating === 'like') return |
142 | 145 | ||
143 | this.videoService.setVideoLike(this.video.id) | 146 | this.videoService.setVideoLike(this.video.id) |
144 | .subscribe( | 147 | .subscribe( |
145 | () => { | 148 | () => { |
146 | // Update the video like attribute | 149 | // Update the video like attribute |
147 | this.updateVideoRating(this.userRating, 'like'); | 150 | this.updateVideoRating(this.userRating, 'like') |
148 | this.userRating = 'like'; | 151 | this.userRating = 'like' |
149 | }, | 152 | }, |
150 | 153 | ||
151 | err => this.notificationsService.error('Error', err.text) | 154 | err => this.notificationsService.error('Error', err.text) |
152 | ); | 155 | ) |
153 | } | 156 | } |
154 | 157 | ||
155 | setDislike() { | 158 | setDislike () { |
156 | if (this.isUserLoggedIn() === false) return; | 159 | if (this.isUserLoggedIn() === false) return |
157 | // Already disliked this video | 160 | // Already disliked this video |
158 | if (this.userRating === 'dislike') return; | 161 | if (this.userRating === 'dislike') return |
159 | 162 | ||
160 | this.videoService.setVideoDislike(this.video.id) | 163 | this.videoService.setVideoDislike(this.video.id) |
161 | .subscribe( | 164 | .subscribe( |
162 | () => { | 165 | () => { |
163 | // Update the video dislike attribute | 166 | // Update the video dislike attribute |
164 | this.updateVideoRating(this.userRating, 'dislike'); | 167 | this.updateVideoRating(this.userRating, 'dislike') |
165 | this.userRating = 'dislike'; | 168 | this.userRating = 'dislike' |
166 | }, | 169 | }, |
167 | 170 | ||
168 | err => this.notificationsService.error('Error', err.text) | 171 | err => this.notificationsService.error('Error', err.text) |
169 | ); | 172 | ) |
170 | } | 173 | } |
171 | 174 | ||
172 | removeVideo(event: Event) { | 175 | removeVideo (event: Event) { |
173 | event.preventDefault(); | 176 | event.preventDefault() |
174 | 177 | ||
175 | this.confirmService.confirm('Do you really want to delete this video?', 'Delete').subscribe( | 178 | this.confirmService.confirm('Do you really want to delete this video?', 'Delete').subscribe( |
176 | res => { | 179 | res => { |
177 | if (res === false) return; | 180 | if (res === false) return |
178 | 181 | ||
179 | this.videoService.removeVideo(this.video.id) | 182 | this.videoService.removeVideo(this.video.id) |
180 | .subscribe( | 183 | .subscribe( |
181 | status => { | 184 | status => { |
182 | this.notificationsService.success('Success', `Video ${this.video.name} deleted.`); | 185 | this.notificationsService.success('Success', `Video ${this.video.name} deleted.`) |
183 | // Go back to the video-list. | 186 | // Go back to the video-list. |
184 | this.router.navigate(['/videos/list']); | 187 | this.router.navigate(['/videos/list']) |
185 | }, | 188 | }, |
186 | 189 | ||
187 | error => this.notificationsService.error('Error', error.text) | 190 | error => this.notificationsService.error('Error', error.text) |
188 | ); | 191 | ) |
189 | } | 192 | } |
190 | ); | 193 | ) |
191 | } | 194 | } |
192 | 195 | ||
193 | blacklistVideo(event: Event) { | 196 | blacklistVideo (event: Event) { |
194 | event.preventDefault(); | 197 | event.preventDefault() |
195 | 198 | ||
196 | this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe( | 199 | this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe( |
197 | res => { | 200 | res => { |
198 | if (res === false) return; | 201 | if (res === false) return |
199 | 202 | ||
200 | this.videoService.blacklistVideo(this.video.id) | 203 | this.videoService.blacklistVideo(this.video.id) |
201 | .subscribe( | 204 | .subscribe( |
202 | status => { | 205 | status => { |
203 | this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`); | 206 | this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`) |
204 | this.router.navigate(['/videos/list']); | 207 | this.router.navigate(['/videos/list']) |
205 | }, | 208 | }, |
206 | 209 | ||
207 | error => this.notificationsService.error('Error', error.text) | 210 | error => this.notificationsService.error('Error', error.text) |
208 | ); | 211 | ) |
209 | } | 212 | } |
210 | ); | 213 | ) |
211 | } | 214 | } |
212 | 215 | ||
213 | showReportModal(event: Event) { | 216 | showReportModal (event: Event) { |
214 | event.preventDefault(); | 217 | event.preventDefault() |
215 | this.videoReportModal.show(); | 218 | this.videoReportModal.show() |
216 | } | 219 | } |
217 | 220 | ||
218 | showShareModal() { | 221 | showShareModal () { |
219 | this.videoShareModal.show(); | 222 | this.videoShareModal.show() |
220 | } | 223 | } |
221 | 224 | ||
222 | showMagnetUriModal(event: Event) { | 225 | showMagnetUriModal (event: Event) { |
223 | event.preventDefault(); | 226 | event.preventDefault() |
224 | this.videoMagnetModal.show(); | 227 | this.videoMagnetModal.show() |
225 | } | 228 | } |
226 | 229 | ||
227 | isUserLoggedIn() { | 230 | isUserLoggedIn () { |
228 | return this.authService.isLoggedIn(); | 231 | return this.authService.isLoggedIn() |
229 | } | 232 | } |
230 | 233 | ||
231 | canUserUpdateVideo() { | 234 | canUserUpdateVideo () { |
232 | return this.video.isUpdatableBy(this.authService.getUser()); | 235 | return this.video.isUpdatableBy(this.authService.getUser()) |
233 | } | 236 | } |
234 | 237 | ||
235 | isVideoRemovable() { | 238 | isVideoRemovable () { |
236 | return this.video.isRemovableBy(this.authService.getUser()); | 239 | return this.video.isRemovableBy(this.authService.getUser()) |
237 | } | 240 | } |
238 | 241 | ||
239 | isVideoBlacklistable() { | 242 | isVideoBlacklistable () { |
240 | return this.video.isBlackistableBy(this.authService.getUser()); | 243 | return this.video.isBlackistableBy(this.authService.getUser()) |
241 | } | 244 | } |
242 | 245 | ||
243 | private checkUserRating() { | 246 | private checkUserRating () { |
244 | // Unlogged users do not have ratings | 247 | // Unlogged users do not have ratings |
245 | if (this.isUserLoggedIn() === false) return; | 248 | if (this.isUserLoggedIn() === false) return |
246 | 249 | ||
247 | this.videoService.getUserVideoRating(this.video.id) | 250 | this.videoService.getUserVideoRating(this.video.id) |
248 | .subscribe( | 251 | .subscribe( |
249 | ratingObject => { | 252 | ratingObject => { |
250 | if (ratingObject) { | 253 | if (ratingObject) { |
251 | this.userRating = ratingObject.rating; | 254 | this.userRating = ratingObject.rating |
252 | } | 255 | } |
253 | }, | 256 | }, |
254 | 257 | ||
255 | err => this.notificationsService.error('Error', err.text) | 258 | err => this.notificationsService.error('Error', err.text) |
256 | ); | 259 | ) |
257 | } | 260 | } |
258 | 261 | ||
259 | private onVideoFetched(video: Video) { | 262 | private onVideoFetched (video: Video) { |
260 | this.video = video; | 263 | this.video = video |
261 | 264 | ||
262 | let observable; | 265 | let observable |
263 | if (this.video.isVideoNSFWForUser(this.authService.getUser())) { | 266 | if (this.video.isVideoNSFWForUser(this.authService.getUser())) { |
264 | observable = this.confirmService.confirm('This video is not safe for work. Are you sure you want to watch it?', 'NSFW'); | 267 | observable = this.confirmService.confirm('This video is not safe for work. Are you sure you want to watch it?', 'NSFW') |
265 | } else { | 268 | } else { |
266 | observable = Observable.of(true); | 269 | observable = Observable.of(true) |
267 | } | 270 | } |
268 | 271 | ||
269 | observable.subscribe( | 272 | observable.subscribe( |
270 | res => { | 273 | res => { |
271 | if (res === false) { | 274 | if (res === false) { |
272 | return this.router.navigate([ '/videos/list' ]); | 275 | return this.router.navigate([ '/videos/list' ]) |
273 | } | 276 | } |
274 | 277 | ||
275 | this.setOpenGraphTags(); | 278 | this.setOpenGraphTags() |
276 | this.loadVideo(); | 279 | this.loadVideo() |
277 | this.checkUserRating(); | 280 | this.checkUserRating() |
278 | } | 281 | } |
279 | ); | 282 | ) |
280 | } | 283 | } |
281 | 284 | ||
282 | private updateVideoRating(oldRating: RateType, newRating: RateType) { | 285 | private updateVideoRating (oldRating: RateType, newRating: RateType) { |
283 | let likesToIncrement = 0; | 286 | let likesToIncrement = 0 |
284 | let dislikesToIncrement = 0; | 287 | let dislikesToIncrement = 0 |
285 | 288 | ||
286 | if (oldRating) { | 289 | if (oldRating) { |
287 | if (oldRating === 'like') likesToIncrement--; | 290 | if (oldRating === 'like') likesToIncrement-- |
288 | if (oldRating === 'dislike') dislikesToIncrement--; | 291 | if (oldRating === 'dislike') dislikesToIncrement-- |
289 | } | 292 | } |
290 | 293 | ||
291 | if (newRating === 'like') likesToIncrement++; | 294 | if (newRating === 'like') likesToIncrement++ |
292 | if (newRating === 'dislike') dislikesToIncrement++; | 295 | if (newRating === 'dislike') dislikesToIncrement++ |
293 | 296 | ||
294 | this.video.likes += likesToIncrement; | 297 | this.video.likes += likesToIncrement |
295 | this.video.dislikes += dislikesToIncrement; | 298 | this.video.dislikes += dislikesToIncrement |
296 | } | 299 | } |
297 | 300 | ||
298 | private loadTooLong() { | 301 | private loadTooLong () { |
299 | this.error = true; | 302 | this.error = true |
300 | console.error('The video load seems to be abnormally long.'); | 303 | console.error('The video load seems to be abnormally long.') |
301 | } | 304 | } |
302 | 305 | ||
303 | private setOpenGraphTags() { | 306 | private setOpenGraphTags () { |
304 | this.metaService.setTitle(this.video.name); | 307 | this.metaService.setTitle(this.video.name) |
305 | 308 | ||
306 | this.metaService.setTag('og:type', 'video'); | 309 | this.metaService.setTag('og:type', 'video') |
307 | 310 | ||
308 | this.metaService.setTag('og:title', this.video.name); | 311 | this.metaService.setTag('og:title', this.video.name) |
309 | this.metaService.setTag('name', this.video.name); | 312 | this.metaService.setTag('name', this.video.name) |
310 | 313 | ||
311 | this.metaService.setTag('og:description', this.video.description); | 314 | this.metaService.setTag('og:description', this.video.description) |
312 | this.metaService.setTag('description', this.video.description); | 315 | this.metaService.setTag('description', this.video.description) |
313 | 316 | ||
314 | this.metaService.setTag('og:image', this.video.thumbnailPath); | 317 | this.metaService.setTag('og:image', this.video.thumbnailPath) |
315 | 318 | ||
316 | this.metaService.setTag('og:duration', this.video.duration.toString()); | 319 | this.metaService.setTag('og:duration', this.video.duration.toString()) |
317 | 320 | ||
318 | this.metaService.setTag('og:site_name', 'PeerTube'); | 321 | this.metaService.setTag('og:site_name', 'PeerTube') |
319 | 322 | ||
320 | this.metaService.setTag('og:url', window.location.href); | 323 | this.metaService.setTag('og:url', window.location.href) |
321 | this.metaService.setTag('url', window.location.href); | 324 | this.metaService.setTag('url', window.location.href) |
322 | } | 325 | } |
323 | 326 | ||
324 | private runInProgress(torrent: any) { | 327 | private runInProgress (torrent: any) { |
325 | // Refresh each second | 328 | // Refresh each second |
326 | this.torrentInfosInterval = window.setInterval(() => { | 329 | this.torrentInfosInterval = window.setInterval(() => { |
327 | this.ngZone.run(() => { | 330 | this.ngZone.run(() => { |
328 | this.downloadSpeed = torrent.downloadSpeed; | 331 | this.downloadSpeed = torrent.downloadSpeed |
329 | this.numPeers = torrent.numPeers; | 332 | this.numPeers = torrent.numPeers |
330 | this.uploadSpeed = torrent.uploadSpeed; | 333 | this.uploadSpeed = torrent.uploadSpeed |
331 | }); | 334 | }) |
332 | }, 1000); | 335 | }, 1000) |
333 | } | 336 | } |
334 | } | 337 | } |
diff --git a/client/src/app/videos/video-watch/webtorrent.service.ts b/client/src/app/videos/video-watch/webtorrent.service.ts index 8936e7992..211894bfd 100644 --- a/client/src/app/videos/video-watch/webtorrent.service.ts +++ b/client/src/app/videos/video-watch/webtorrent.service.ts | |||
@@ -1,33 +1,33 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Subject } from 'rxjs/Subject'; | 2 | import { Subject } from 'rxjs/Subject' |
3 | 3 | ||
4 | import * as WebTorrent from 'webtorrent'; | 4 | import * as WebTorrent from 'webtorrent' |
5 | 5 | ||
6 | @Injectable() | 6 | @Injectable() |
7 | export class WebTorrentService { | 7 | export class WebTorrentService { |
8 | errors = new Subject<Error>(); | 8 | errors = new Subject<Error>() |
9 | warnings = new Subject<Error>(); | 9 | warnings = new Subject<Error>() |
10 | 10 | ||
11 | // TODO: use WebTorrent @type | 11 | // TODO: use WebTorrent @type |
12 | // private client: WebTorrent.Client; | 12 | // private client: WebTorrent.Client |
13 | private client: any; | 13 | private client: any |
14 | 14 | ||
15 | constructor() { | 15 | constructor () { |
16 | this.client = new WebTorrent({ dht: false }); | 16 | this.client = new WebTorrent({ dht: false }) |
17 | 17 | ||
18 | this.client.on('error', (err) => this.errors.next(err)); | 18 | this.client.on('error', (err) => this.errors.next(err)) |
19 | this.client.on('warning', (err) => this.warnings.next(err)); | 19 | this.client.on('warning', (err) => this.warnings.next(err)) |
20 | } | 20 | } |
21 | 21 | ||
22 | add(magnetUri: string, callback: Function) { | 22 | add (magnetUri: string, callback: Function) { |
23 | return this.client.add(magnetUri, callback); | 23 | return this.client.add(magnetUri, callback) |
24 | } | 24 | } |
25 | 25 | ||
26 | remove(magnetUri: string) { | 26 | remove (magnetUri: string) { |
27 | return this.client.remove(magnetUri); | 27 | return this.client.remove(magnetUri) |
28 | } | 28 | } |
29 | 29 | ||
30 | has(magnetUri: string) { | 30 | has (magnetUri: string) { |
31 | return this.client.get(magnetUri) !== null; | 31 | return this.client.get(magnetUri) !== null |
32 | } | 32 | } |
33 | } | 33 | } |
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts index 70968b4d1..7d002abde 100644 --- a/client/src/app/videos/videos-routing.module.ts +++ b/client/src/app/videos/videos-routing.module.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router'; | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | 3 | ||
4 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit'; | 4 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit' |
5 | import { VideoListComponent } from './video-list'; | 5 | import { VideoListComponent } from './video-list' |
6 | import { VideosComponent } from './videos.component'; | 6 | import { VideosComponent } from './videos.component' |
7 | import { VideoWatchComponent } from './video-watch'; | 7 | import { VideoWatchComponent } from './video-watch' |
8 | 8 | ||
9 | const videosRoutes: Routes = [ | 9 | const videosRoutes: Routes = [ |
10 | { | 10 | { |
@@ -48,7 +48,7 @@ const videosRoutes: Routes = [ | |||
48 | } | 48 | } |
49 | ] | 49 | ] |
50 | } | 50 | } |
51 | ]; | 51 | ] |
52 | 52 | ||
53 | @NgModule({ | 53 | @NgModule({ |
54 | imports: [ RouterModule.forChild(videosRoutes) ], | 54 | imports: [ RouterModule.forChild(videosRoutes) ], |
diff --git a/client/src/app/videos/videos.component.ts b/client/src/app/videos/videos.component.ts index 591e7523d..972c2221f 100644 --- a/client/src/app/videos/videos.component.ts +++ b/client/src/app/videos/videos.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | template: '<router-outlet></router-outlet>' | 4 | template: '<router-outlet></router-outlet>' |
diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts index adfbe7031..75a8dd24f 100644 --- a/client/src/app/videos/videos.module.ts +++ b/client/src/app/videos/videos.module.ts | |||
@@ -1,20 +1,20 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | 2 | ||
3 | import { TagInputModule } from 'ng2-tag-input'; | 3 | import { TagInputModule } from 'ng2-tag-input' |
4 | 4 | ||
5 | import { VideosRoutingModule } from './videos-routing.module'; | 5 | import { VideosRoutingModule } from './videos-routing.module' |
6 | import { VideosComponent } from './videos.component'; | 6 | import { VideosComponent } from './videos.component' |
7 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit'; | 7 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit' |
8 | import { LoaderComponent, VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list'; | 8 | import { LoaderComponent, VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list' |
9 | import { | 9 | import { |
10 | VideoWatchComponent, | 10 | VideoWatchComponent, |
11 | VideoMagnetComponent, | 11 | VideoMagnetComponent, |
12 | VideoReportComponent, | 12 | VideoReportComponent, |
13 | VideoShareComponent, | 13 | VideoShareComponent, |
14 | WebTorrentService | 14 | WebTorrentService |
15 | } from './video-watch'; | 15 | } from './video-watch' |
16 | import { VideoService } from './shared'; | 16 | import { VideoService } from './shared' |
17 | import { SharedModule } from '../shared'; | 17 | import { SharedModule } from '../shared' |
18 | 18 | ||
19 | @NgModule({ | 19 | @NgModule({ |
20 | imports: [ | 20 | imports: [ |