diff --git a/client/package.json b/client/package.json
index d69a7b10b..caec34e44 100644
--- a/client/package.json
+++ b/client/package.json
@@ -62,7 +62,6 @@
"json-loader": "^0.5.4",
"ng-router-loader": "^2.0.0",
"ng2-file-upload": "^1.1.4-2",
- "ng2-smart-table": "1.2.1",
"ngc-webpack": "3.2.2",
"ngx-bootstrap": "1.9.1",
"ngx-chips": "1.5.3",
@@ -97,6 +96,7 @@
"add-asset-html-webpack-plugin": "^2.0.1",
"codelyzer": "^3.0.0-beta.4",
"extract-text-webpack-plugin": "^3.0.0",
+ "primeng": "^4.2.0",
"purify-css": "^1.2.5",
"purifycss-webpack": "^0.7.0",
"standard": "^10.0.0",
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 0449d26a9..02543d393 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
@@ -93,8 +93,9 @@ export class FriendAddComponent implements OnInit {
this.friendService.makeFriends(notEmptyHosts).subscribe(
status => {
- this.notificationsService.success('Sucess', 'Make friends request sent!')
- this.router.navigate([ '/admin/friends/list' ])
+ this.notificationsService.success('Success', 'Make friends request sent!')
+ // Wait requests between pods
+ setTimeout(() => this.router.navigate([ '/admin/friends/list' ]), 1000)
},
err => this.notificationsService.error('Error', err.text)
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.html b/client/src/app/+admin/friends/friend-list/friend-list.component.html
index 7b9fff304..7887bc5e3 100644
--- a/client/src/app/+admin/friends/friend-list/friend-list.component.html
+++ b/client/src/app/+admin/friends/friend-list/friend-list.component.html
@@ -2,13 +2,24 @@
Friends list
-
+
+
+
+
+
+
+
+
+
+
+
+
Quit friends
-
+
Make friends
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 822a112cc..6a8bd492c 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,71 +1,31 @@
-import { Component } from '@angular/core'
+import { Component, OnInit } from '@angular/core'
import { NotificationsService } from 'angular2-notifications'
-import { ServerDataSource } from 'ng2-smart-table'
import { ConfirmService } from '../../../core'
-import { Utils } from '../../../shared'
import { FriendService } from '../shared'
import { Pod } from '../../../../../../shared'
@Component({
selector: 'my-friend-list',
templateUrl: './friend-list.component.html',
- styleUrls: [ './friend-list.component.scss' ]
+ styleUrls: ['./friend-list.component.scss']
})
-export class FriendListComponent {
- friendsSource = null
- tableSettings = {
- mode: 'external',
- attr: {
- class: 'table-hover'
- },
- hideSubHeader: true,
- actions: {
- position: 'right',
- add: false,
- edit: false,
- delete: true
- },
- delete: {
- deleteButtonContent: Utils.getRowDeleteButton()
- },
- columns: {
- id: {
- title: 'ID',
- sort: false,
- sortDirection: 'asc'
- },
- host: {
- title: 'Host',
- sort: false
- },
- email: {
- title: 'Email',
- sort: false
- },
- score: {
- title: 'Score',
- sort: false
- },
- createdAt: {
- title: 'Created Date',
- sort: false,
- valuePrepareFunction: Utils.dateToHuman
- }
- }
- }
+export class FriendListComponent implements OnInit {
+ friends: Pod[] = []
constructor (
private notificationsService: NotificationsService,
private confirmService: ConfirmService,
private friendService: FriendService
- ) {
- this.friendsSource = this.friendService.getDataSource()
+ ) {}
+
+ ngOnInit () {
+ this.loadData()
}
hasFriends () {
- return this.friendsSource.count() !== 0
+ return this.friends.length !== 0
}
quitFriends () {
@@ -77,32 +37,42 @@ export class FriendListComponent {
this.friendService.quitFriends().subscribe(
status => {
this.notificationsService.success('Success', 'Friends left!')
- this.friendsSource.refresh()
+ this.loadData()
},
- err => this.notificationsService.error('Error', err.text)
+ err => this.notificationsService.error('Error', err)
)
}
)
}
- removeFriend ({ data }) {
+ removeFriend (friend: Pod) {
const confirmMessage = 'Do you really want to remove this friend ? All its videos will be deleted.'
- const friend: Pod = data
this.confirmService.confirm(confirmMessage, 'Remove').subscribe(
res => {
if (res === false) return
this.friendService.removeFriend(friend).subscribe(
- status => {
- this.notificationsService.success('Success', 'Friend removed')
- this.friendsSource.refresh()
- },
+ status => {
+ this.notificationsService.success('Success', 'Friend removed')
+ this.loadData()
+ },
- err => this.notificationsService.error('Error', err.text)
- )
+ err => this.notificationsService.error('Error', err)
+ )
}
)
}
+
+ private loadData () {
+ this.friendService.getFriends()
+ .subscribe(
+ resultList => {
+ this.friends = resultList.data
+ },
+
+ err => this.notificationsService.error('Error', err)
+ )
+ }
}
diff --git a/client/src/app/+admin/friends/shared/friend.service.ts b/client/src/app/+admin/friends/shared/friend.service.ts
index 9b3ff04b1..45607e28d 100644
--- a/client/src/app/+admin/friends/shared/friend.service.ts
+++ b/client/src/app/+admin/friends/shared/friend.service.ts
@@ -1,24 +1,24 @@
import { Injectable } from '@angular/core'
-import { Observable } from 'rxjs/Observable'
+import { HttpClient } from '@angular/common/http'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/map'
-import { ServerDataSource } from 'ng2-smart-table'
-
-import { AuthHttp, RestExtractor, RestDataSource, ResultList } from '../../../shared'
-import { Pod } from '../../../../../../shared'
+import { RestExtractor, } from '../../../shared'
+import { Pod, ResultList } from '../../../../../../shared'
@Injectable()
export class FriendService {
private static BASE_FRIEND_URL = API_URL + '/api/v1/pods/'
constructor (
- private authHttp: AuthHttp,
+ private authHttp: HttpClient,
private restExtractor: RestExtractor
) {}
- getDataSource () {
- return new RestDataSource(this.authHttp, FriendService.BASE_FRIEND_URL)
+ getFriends () {
+ return this.authHttp.get>(FriendService.BASE_FRIEND_URL)
+ .map(res => this.restExtractor.convertResultListDateToHuman(res))
+ .catch(res => this.restExtractor.handleError(res))
}
makeFriends (notEmptyHosts: String[]) {
@@ -28,18 +28,18 @@ export class FriendService {
return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'make-friends', body)
.map(this.restExtractor.extractDataBool)
- .catch((res) => this.restExtractor.handleError(res))
+ .catch(res => this.restExtractor.handleError(res))
}
quitFriends () {
return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quit-friends')
- .map(res => res.status)
- .catch((res) => this.restExtractor.handleError(res))
+ .map(this.restExtractor.extractDataBool)
+ .catch(res => this.restExtractor.handleError(res))
}
removeFriend (friend: Pod) {
return this.authHttp.delete(FriendService.BASE_FRIEND_URL + friend.id)
.map(this.restExtractor.extractDataBool)
- .catch((res) => this.restExtractor.handleError(res))
+ .catch(res => this.restExtractor.handleError(res))
}
}
diff --git a/client/src/app/+admin/request-schedulers/shared/request-schedulers.service.ts b/client/src/app/+admin/request-schedulers/shared/request-schedulers.service.ts
index e9b166f78..44d9cbc3e 100644
--- a/client/src/app/+admin/request-schedulers/shared/request-schedulers.service.ts
+++ b/client/src/app/+admin/request-schedulers/shared/request-schedulers.service.ts
@@ -1,10 +1,11 @@
import { Injectable } from '@angular/core'
+import { HttpClient } from '@angular/common/http'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/map'
import { RequestSchedulerStats } from '../../../../../../shared'
-import { AuthHttp, RestExtractor } from '../../../shared'
+import { RestExtractor } from '../../../shared'
import { RequestSchedulerStatsAttributes } from './request-schedulers-stats-attributes.model'
@Injectable()
@@ -12,19 +13,18 @@ export class RequestSchedulersService {
private static BASE_REQUEST_URL = API_URL + '/api/v1/request-schedulers/'
constructor (
- private authHttp: AuthHttp,
+ private authHttp: HttpClient,
private restExtractor: RestExtractor
) {}
- getStats (): Observable {
- return this.authHttp.get(RequestSchedulersService.BASE_REQUEST_URL + 'stats')
- .map(this.restExtractor.extractDataGet)
- .map(this.buildRequestObjects)
- .catch((res) => this.restExtractor.handleError(res))
+ getStats () {
+ return this.authHttp.get(RequestSchedulersService.BASE_REQUEST_URL + 'stats')
+ .map(res => this.buildRequestObjects(res))
+ .catch(res => this.restExtractor.handleError(res))
}
private buildRequestObjects (data: RequestSchedulerStats) {
- const requestSchedulers = {}
+ const requestSchedulers: { [ id: string ]: RequestSchedulerStatsAttributes } = {}
Object.keys(data).forEach(requestSchedulerName => {
requestSchedulers[requestSchedulerName] = new RequestSchedulerStatsAttributes(data[requestSchedulerName])
diff --git a/client/src/app/+admin/users/shared/user.service.ts b/client/src/app/+admin/users/shared/user.service.ts
index 999013bcc..a4b89bf1d 100644
--- a/client/src/app/+admin/users/shared/user.service.ts
+++ b/client/src/app/+admin/users/shared/user.service.ts
@@ -1,11 +1,14 @@
import { Injectable } from '@angular/core'
+import { HttpClient, HttpParams } from '@angular/common/http'
+import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/map'
+import { SortMeta } from 'primeng/primeng'
import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'
-import { AuthHttp, RestExtractor, RestDataSource, User } from '../../../shared'
-import { UserCreate, UserUpdate } from '../../../../../../shared'
+import { RestExtractor, User, RestPagination, RestService } from '../../../shared'
+import { UserCreate, UserUpdate, ResultList } from '../../../../../../shared'
@Injectable()
export class UserService {
@@ -13,53 +16,52 @@ export class UserService {
private bytesPipe = new BytesPipe()
constructor (
- private authHttp: AuthHttp,
+ private authHttp: HttpClient,
+ private restService: RestService,
private restExtractor: RestExtractor
) {}
addUser (userCreate: UserCreate) {
return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
.map(this.restExtractor.extractDataBool)
- .catch(this.restExtractor.handleError)
+ .catch(err => this.restExtractor.handleError(err))
}
updateUser (userId: number, userUpdate: UserUpdate) {
return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
- .map(this.restExtractor.extractDataBool)
- .catch(this.restExtractor.handleError)
+ .map(this.restExtractor.extractDataBool)
+ .catch(err => this.restExtractor.handleError(err))
}
getUser (userId: number) {
- return this.authHttp.get(UserService.BASE_USERS_URL + userId)
- .map(this.restExtractor.extractDataGet)
- .catch(this.restExtractor.handleError)
+ return this.authHttp.get(UserService.BASE_USERS_URL + userId)
+ .catch(err => this.restExtractor.handleError(err))
}
- getDataSource () {
- return new RestDataSource(this.authHttp, UserService.BASE_USERS_URL, this.formatDataSource.bind(this))
+ getUsers (pagination: RestPagination, sort: SortMeta): Observable> {
+ let params = new HttpParams()
+ params = this.restService.addRestGetParams(params, pagination, sort)
+
+ return this.authHttp.get>(UserService.BASE_USERS_URL, { params })
+ .map(res => this.restExtractor.convertResultListDateToHuman(res))
+ .map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this)))
+ .catch(err => this.restExtractor.handleError(err))
}
removeUser (user: User) {
return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
}
- private formatDataSource (users: User[]) {
- const newUsers = []
+ private formatUser (user: User) {
+ let videoQuota
+ if (user.videoQuota === -1) {
+ videoQuota = 'Unlimited'
+ } else {
+ videoQuota = this.bytesPipe.transform(user.videoQuota)
+ }
- users.forEach(user => {
- let videoQuota
- if (user.videoQuota === -1) {
- videoQuota = 'Unlimited'
- } else {
- videoQuota = this.bytesPipe.transform(user.videoQuota)
- }
-
- const newUser = Object.assign(user, {
- videoQuota
- })
- newUsers.push(newUser)
+ return Object.assign(user, {
+ videoQuota
})
-
- return newUsers
}
}
diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html
index eb5bc9d4a..2944e3cbf 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.html
+++ b/client/src/app/+admin/users/user-list/user-list.component.html
@@ -3,10 +3,29 @@
Users list
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 7187a2008..c3fa55825 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,82 +1,37 @@
-import { Component } from '@angular/core'
+import { Component, OnInit } from '@angular/core'
+import { SortMeta } from 'primeng/primeng'
import { NotificationsService } from 'angular2-notifications'
import { ConfirmService } from '../../../core'
-import { RestDataSource, User, Utils } from '../../../shared'
+import { RestTable, RestPagination, User } from '../../../shared'
import { UserService } from '../shared'
-import { Router } from '@angular/router'
@Component({
selector: 'my-user-list',
templateUrl: './user-list.component.html',
styleUrls: [ './user-list.component.scss' ]
})
-export class UserListComponent {
- usersSource: RestDataSource = null
- tableSettings = {
- mode: 'external',
- attr: {
- class: 'table-hover'
- },
- hideSubHeader: true,
- actions: {
- position: 'right',
- add: false,
- edit: true,
- delete: true
- },
- delete: {
- deleteButtonContent: Utils.getRowDeleteButton()
- },
- edit: {
- editButtonContent: Utils.getRowEditButton()
- },
- pager: {
- display: true,
- perPage: 10
- },
- columns: {
- id: {
- title: 'ID',
- sortDirection: 'asc'
- },
- username: {
- title: 'Username'
- },
- email: {
- title: 'Email'
- },
- videoQuota: {
- title: 'Video quota'
- },
- role: {
- title: 'Role',
- sort: false
- },
- createdAt: {
- title: 'Created Date',
- valuePrepareFunction: Utils.dateToHuman
- }
- }
- }
+export class UserListComponent extends RestTable implements OnInit {
+ users: User[] = []
+ totalRecords = 0
+ rowsPerPage = 10
+ sort: SortMeta = { field: 'id', order: 1 }
+ pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor (
- private router: Router,
private notificationsService: NotificationsService,
private confirmService: ConfirmService,
private userService: UserService
) {
- this.usersSource = this.userService.getDataSource()
+ super()
}
- editUser ({ data }: { data: User }) {
- this.router.navigate([ '/admin', 'users', data.id, 'update' ])
+ ngOnInit () {
+ this.loadData()
}
- removeUser ({ data }: { data: User }) {
- const user = data
-
+ removeUser (user: User) {
if (user.username === 'root') {
this.notificationsService.error('Error', 'You cannot delete root.')
return
@@ -89,12 +44,28 @@ export class UserListComponent {
this.userService.removeUser(user).subscribe(
() => {
this.notificationsService.success('Success', `User ${user.username} deleted.`)
- this.usersSource.refresh()
+ this.loadData()
},
- err => this.notificationsService.error('Error', err.text)
+ err => this.notificationsService.error('Error', err)
)
}
)
}
+
+ getRouterUserEditLink (user: User) {
+ return [ '/admin', 'users', user.id, 'update' ]
+ }
+
+ protected loadData () {
+ this.userService.getUsers(this.pagination, this.sort)
+ .subscribe(
+ resultList => {
+ this.users = resultList.data
+ this.totalRecords = resultList.total
+ },
+
+ err => this.notificationsService.error('Error', err)
+ )
+ }
}
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
index c6723a734..e73f38112 100644
--- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
+++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
@@ -3,9 +3,21 @@
Video abuses list
-
+
+
+
+
+
+
+
+ {{ videoAbuse.videoId }}
+
+
+
+
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 7c838fbf0..cc9c1bdf4 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,72 +1,46 @@
-import { Component } from '@angular/core'
+import { Component, OnInit } from '@angular/core'
import { NotificationsService } from 'angular2-notifications'
+import { SortMeta } from 'primeng/primeng'
-import { Utils, VideoAbuseService } from '../../../shared'
-import { VideoAbuse } from '../../../../../shared'
+import { RestTable, RestPagination, VideoAbuseService } from '../../../shared'
+import { VideoAbuse } from '../../../../../../shared'
@Component({
selector: 'my-video-abuse-list',
templateUrl: './video-abuse-list.component.html'
})
-export class VideoAbuseListComponent {
- videoAbusesSource = null
- tableSettings = {
- mode: 'external',
- attr: {
- class: 'table-hover'
- },
- hideSubHeader: true,
- actions: {
- position: 'right',
- add: false,
- edit: false,
- delete: false
- },
- pager: {
- display: true,
- perPage: 10
- },
- columns: {
- id: {
- title: 'ID',
- sortDirection: 'asc'
- },
- reason: {
- title: 'Reason',
- sort: false
- },
- reporterPodHost: {
- title: 'Reporter pod host',
- sort: false
- },
- reporterUsername: {
- title: 'Reporter username',
- sort: false
- },
- videoId: {
- title: 'Video',
- type: 'html',
- sort: false,
- valuePrepareFunction: this.buildVideoLink
- },
- createdAt: {
- title: 'Created Date',
- valuePrepareFunction: Utils.dateToHuman
- }
- }
- }
+export class VideoAbuseListComponent extends RestTable implements OnInit {
+ videoAbuses: VideoAbuse[] = []
+ totalRecords = 0
+ rowsPerPage = 1
+ sort: SortMeta = { field: 'id', order: 1 }
+ pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor (
private notificationsService: NotificationsService,
private videoAbuseService: VideoAbuseService
) {
- this.videoAbusesSource = this.videoAbuseService.getDataSource()
+ super()
}
- buildVideoLink (videoId: string) {
- // TODO: transform to routerLink
- // https://github.com/akveo/ng2-smart-table/issues/57
- return `${videoId}`
+ ngOnInit () {
+ this.loadData()
+ }
+
+ getRouterVideoLink (videoId: number) {
+ return [ '/videos', videoId ]
+ }
+
+ protected loadData () {
+ return this.videoAbuseService.getVideoAbuses(this.pagination, this.sort)
+ .subscribe(
+ resultList => {
+ this.videoAbuses = resultList.data
+ this.totalRecords = resultList.total
+ },
+
+ err => this.notificationsService.error('Error', err)
+ )
}
}
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 8cbed5009..78e365a62 100644
--- a/client/src/app/account/account-details/account-details.component.ts
+++ b/client/src/app/account/account-details/account-details.component.ts
@@ -59,7 +59,7 @@ export class AccountDetailsComponent extends FormReactive implements OnInit {
() => {
this.notificationsService.success('Success', 'Information updated.')
- this.authService.refreshUserInformations()
+ this.authService.refreshUserInformation()
},
err => this.error = err
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index a90654e26..57bf64f69 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -36,6 +36,8 @@ export class AppComponent implements OnInit {
) {}
ngOnInit () {
+ this.authService.loadClientCredentials()
+
if (this.authService.isLoggedIn()) {
// The service will automatically redirect to the login page if the token is not valid anymore
this.userService.checkTokenValidity()
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts
index 804a7a71e..6aa56b8a7 100644
--- a/client/src/app/app.module.ts
+++ b/client/src/app/app.module.ts
@@ -7,8 +7,6 @@ import {
} from '@angularclass/hmr'
import { MetaModule, MetaLoader, MetaStaticLoader, PageTitlePositioning } from '@ngx-meta/core'
-// TODO: remove, we need this to avoid error in ng2-smart-table
-import 'rxjs/add/operator/toPromise'
import 'bootstrap-loader'
import { ENV_PROVIDERS } from './environment'
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index de9e14b2d..522efb23c 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -1,8 +1,8 @@
import { Injectable } from '@angular/core'
-import { Headers, Http, Response, URLSearchParams } from '@angular/http'
import { Router } from '@angular/router'
import { Observable } from 'rxjs/Observable'
import { Subject } from 'rxjs/Subject'
+import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/mergeMap'
import 'rxjs/add/observable/throw'
@@ -11,15 +11,35 @@ import { NotificationsService } from 'angular2-notifications'
import { AuthStatus } from './auth-status.model'
import { AuthUser } from './auth-user.model'
-import { OAuthClientLocal, UserRole } from '../../../../../shared'
+import { OAuthClientLocal, UserRole, UserRefreshToken } from '../../../../../shared'
// Do not use the barrel (dependency loop)
import { RestExtractor } from '../../shared/rest'
+import { UserLogin } from '../../../../../shared/models/users/user-login.model'
+import { User } from '../../shared/users/user.model'
+
+interface UserLoginWithUsername extends UserLogin {
+ access_token: string
+ refresh_token: string
+ token_type: string
+ username: string
+}
+
+interface UserLoginWithUserInformation extends UserLogin {
+ access_token: string
+ refresh_token: string
+ token_type: string
+ username: string
+ id: number
+ role: UserRole
+ displayNSFW: boolean
+ email: string
+}
@Injectable()
export class AuthService {
private static BASE_CLIENT_URL = API_URL + '/api/v1/oauth-clients/local'
private static BASE_TOKEN_URL = API_URL + '/api/v1/users/token'
- private static BASE_USER_INFORMATIONS_URL = API_URL + '/api/v1/users/me'
+ private static BASE_USER_INFORMATION_URL = API_URL + '/api/v1/users/me'
loginChangedSource: Observable
@@ -29,7 +49,7 @@ export class AuthService {
private user: AuthUser = null
constructor (
- private http: Http,
+ private http: HttpClient,
private notificationsService: NotificationsService,
private restExtractor: RestExtractor,
private router: Router
@@ -37,32 +57,33 @@ export class AuthService {
this.loginChanged = new Subject()
this.loginChangedSource = this.loginChanged.asObservable()
- // Fetch the client_id/client_secret
- // FIXME: save in local storage?
- this.http.get(AuthService.BASE_CLIENT_URL)
- .map(this.restExtractor.extractDataGet)
- .catch(res => this.restExtractor.handleError(res))
- .subscribe(
- (result: OAuthClientLocal) => {
- this.clientId = result.client_id
- this.clientSecret = result.client_secret
- console.log('Client credentials loaded.')
- },
-
- error => {
- let errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`
- errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'
-
- // We put a bigger timeout
- // This is an important message
- this.notificationsService.error('Error', errorMessage, { timeOut: 7000 })
- }
- )
-
// Return null if there is nothing to load
this.user = AuthUser.load()
}
+ loadClientCredentials () {
+ // Fetch the client_id/client_secret
+ // FIXME: save in local storage?
+ this.http.get(AuthService.BASE_CLIENT_URL)
+ .catch(res => this.restExtractor.handleError(res))
+ .subscribe(
+ res => {
+ this.clientId = res.client_id
+ this.clientSecret = res.client_secret
+ console.log('Client credentials loaded.')
+ },
+
+ error => {
+ let errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`
+ errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'
+
+ // We put a bigger timeout
+ // This is an important message
+ this.notificationsService.error('Error', errorMessage, { timeOut: 7000 })
+ }
+ )
+ }
+
getRefreshToken () {
if (this.user === null) return null
@@ -70,7 +91,11 @@ export class AuthService {
}
getRequestHeaderValue () {
- return `${this.getTokenType()} ${this.getAccessToken()}`
+ const accessToken = this.getAccessToken()
+
+ if (accessToken === null) return null
+
+ return `${this.getTokenType()} ${accessToken}`
}
getAccessToken () {
@@ -96,39 +121,26 @@ export class AuthService {
}
isLoggedIn () {
- if (this.getAccessToken()) {
- return true
- } else {
- return false
- }
+ return !!this.getAccessToken()
}
login (username: string, password: string) {
- let body = new URLSearchParams()
- body.set('client_id', this.clientId)
- body.set('client_secret', this.clientSecret)
- body.set('response_type', 'code')
- body.set('grant_type', 'password')
- body.set('scope', 'upload')
- body.set('username', username)
- body.set('password', password)
+ // Form url encoded
+ const body = new HttpParams().set('client_id', this.clientId)
+ .set('client_secret', this.clientSecret)
+ .set('response_type', 'code')
+ .set('grant_type', 'password')
+ .set('scope', 'upload')
+ .set('username', username)
+ .set('password', password)
- let headers = new Headers()
- headers.append('Content-Type', 'application/x-www-form-urlencoded')
+ const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
- let options = {
- headers: headers
- }
-
- return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options)
- .map(this.restExtractor.extractDataGet)
- .map(res => {
- res.username = username
- return res
- })
- .flatMap(res => this.mergeUserInformations(res))
+ return this.http.post(AuthService.BASE_TOKEN_URL, body, { headers })
+ .map(res => Object.assign(res, { username }))
+ .flatMap(res => this.mergeUserInformation(res))
.map(res => this.handleLogin(res))
- .catch((res) => this.restExtractor.handleError(res))
+ .catch(res => this.restExtractor.handleError(res))
}
logout () {
@@ -145,33 +157,26 @@ export class AuthService {
const refreshToken = this.getRefreshToken()
- let body = new URLSearchParams()
- body.set('refresh_token', refreshToken)
- body.set('client_id', this.clientId)
- body.set('client_secret', this.clientSecret)
- body.set('response_type', 'code')
- body.set('grant_type', 'refresh_token')
+ // Form url encoded
+ const body = new HttpParams().set('refresh_token', refreshToken)
+ .set('client_id', this.clientId)
+ .set('client_secret', this.clientSecret)
+ .set('response_type', 'code')
+ .set('grant_type', 'refresh_token')
- let headers = new Headers()
- headers.append('Content-Type', 'application/x-www-form-urlencoded')
+ const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
- let options = {
- headers: headers
- }
-
- return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options)
- .map(this.restExtractor.extractDataGet)
+ return this.http.post(AuthService.BASE_TOKEN_URL, body, { headers })
.map(res => this.handleRefreshToken(res))
- .catch((res: Response) => {
+ .catch(res => {
// The refresh token is invalid?
- if (res.status === 400 && res.json() && res.json().error === 'invalid_grant') {
+ if (res.status === 400 && res.error === 'invalid_grant') {
console.error('Cannot refresh token -> logout...')
this.logout()
this.router.navigate(['/login'])
return Observable.throw({
- json: () => '',
- text: () => 'You need to reconnect.'
+ error: 'You need to reconnect.'
})
}
@@ -179,7 +184,7 @@ export class AuthService {
})
}
- refreshUserInformations () {
+ refreshUserInformation () {
const obj = {
access_token: this.user.getAccessToken(),
refresh_token: null,
@@ -187,7 +192,7 @@ export class AuthService {
username: this.user.username
}
- this.mergeUserInformations (obj)
+ this.mergeUserInformation(obj)
.subscribe(
res => {
this.user.displayNSFW = res.displayNSFW
@@ -198,42 +203,25 @@ export class AuthService {
)
}
- private mergeUserInformations (obj: {
- access_token: string,
- refresh_token: string,
- token_type: string,
- username: string
- }) {
- // Do not call authHttp here to avoid circular dependencies headaches
+ private mergeUserInformation (obj: UserLoginWithUsername): Observable {
+ // User is not loaded yet, set manually auth header
+ const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`)
- const headers = new Headers()
- headers.set('Authorization', `Bearer ${obj.access_token}`)
+ return this.http.get(AuthService.BASE_USER_INFORMATION_URL, { headers })
+ .map(res => {
+ const newProperties = {
+ id: res.id as number,
+ role: res.role as UserRole,
+ displayNSFW: res.displayNSFW as boolean,
+ email: res.email as string
+ }
- return this.http.get(AuthService.BASE_USER_INFORMATIONS_URL, { headers })
- .map(res => res.json())
- .map(res => {
- const newProperties = {
- id: res.id as number,
- role: res.role as UserRole,
- displayNSFW: res.displayNSFW as boolean,
- email: res.email as string
- }
-
- return Object.assign(obj, newProperties)
- }
+ return Object.assign(obj, newProperties)
+ }
)
}
- private handleLogin (obj: {
- access_token: string,
- refresh_token: string,
- token_type: string,
- id: number,
- username: string,
- email: string,
- role: UserRole,
- displayNSFW: boolean
- }) {
+ private handleLogin (obj: UserLoginWithUserInformation) {
const id = obj.id
const username = obj.username
const role = obj.role
@@ -251,7 +239,7 @@ export class AuthService {
this.setStatus(AuthStatus.LoggedIn)
}
- private handleRefreshToken (obj: { access_token: string, refresh_token: string }) {
+ private handleRefreshToken (obj: UserRefreshToken) {
this.user.refreshTokens(obj.access_token, obj.refresh_token)
this.user.save()
}
@@ -259,5 +247,4 @@ export class AuthService {
private setStatus (status: AuthStatus) {
this.loginChanged.next(status)
}
-
}
diff --git a/client/src/app/core/config/config.service.ts b/client/src/app/core/config/config.service.ts
index acdc12cc6..3c479bcb8 100644
--- a/client/src/app/core/config/config.service.ts
+++ b/client/src/app/core/config/config.service.ts
@@ -1,7 +1,6 @@
import { Injectable } from '@angular/core'
-import { Http } from '@angular/http'
+import { HttpClient } from '@angular/common/http'
-import { RestExtractor } from '../../shared/rest'
import { ServerConfig } from '../../../../../shared'
@Injectable()
@@ -14,17 +13,11 @@ export class ConfigService {
}
}
- constructor (
- private http: Http,
- private restExtractor: RestExtractor
- ) {}
+ constructor (private http: HttpClient) {}
loadConfig () {
- this.http.get(ConfigService.BASE_CONFIG_URL)
- .map(this.restExtractor.extractDataGet)
- .subscribe(data => {
- this.config = data
- })
+ this.http.get(ConfigService.BASE_CONFIG_URL)
+ .subscribe(data => this.config = data)
}
getConfig () {
diff --git a/client/src/app/shared/auth/auth-http.service.ts b/client/src/app/shared/auth/auth-http.service.ts
deleted file mode 100644
index 0fbaab0a8..000000000
--- a/client/src/app/shared/auth/auth-http.service.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { Injectable } from '@angular/core'
-import {
- ConnectionBackend,
- Headers,
- Http,
- Request,
- RequestMethod,
- RequestOptions,
- RequestOptionsArgs,
- Response,
- XHRBackend
-} from '@angular/http'
-import { Observable } from 'rxjs/Observable'
-
-import { AuthService } from '../../core'
-
-@Injectable()
-export class AuthHttp extends Http {
- constructor (backend: ConnectionBackend, defaultOptions: RequestOptions, private authService: AuthService) {
- super(backend, defaultOptions)
- }
-
- request (url: string | Request, options?: RequestOptionsArgs): Observable {
- if (!options) options = {}
-
- options.headers = new Headers()
- this.setAuthorizationHeader(options.headers)
-
- return super.request(url, options)
- .catch((err) => {
- if (err.status === 401) {
- return this.handleTokenExpired(url, options)
- }
-
- return Observable.throw(err)
- })
- }
-
- delete (url: string, options?: RequestOptionsArgs): Observable {
- if (!options) options = {}
- options.method = RequestMethod.Delete
-
- return this.request(url, options)
- }
-
- get (url: string, options?: RequestOptionsArgs): Observable {
- if (!options) options = {}
- options.method = RequestMethod.Get
-
- return this.request(url, options)
- }
-
- post (url: string, body: any, options?: RequestOptionsArgs): Observable {
- if (!options) options = {}
- options.method = RequestMethod.Post
- options.body = body
-
- return this.request(url, options)
- }
-
- put (url: string, body: any, options?: RequestOptionsArgs): Observable {
- if (!options) options = {}
- options.method = RequestMethod.Put
- options.body = body
-
- return this.request(url, options)
- }
-
- private handleTokenExpired (url: string | Request, options: RequestOptionsArgs) {
- return this.authService.refreshAccessToken()
- .flatMap(() => {
- this.setAuthorizationHeader(options.headers)
-
- return super.request(url, options)
- })
- }
-
- private setAuthorizationHeader (headers: Headers) {
- headers.set('Authorization', this.authService.getRequestHeaderValue())
- }
-}
-
-export function useFactory (backend: XHRBackend, defaultOptions: RequestOptions, authService: AuthService) {
- return new AuthHttp(backend, defaultOptions, authService)
-}
-
-export const AUTH_HTTP_PROVIDERS = [
- {
- provide: AuthHttp,
- useFactory,
- deps: [ XHRBackend, RequestOptions, AuthService ]
- }
-]
diff --git a/client/src/app/shared/auth/auth-interceptor.service.ts b/client/src/app/shared/auth/auth-interceptor.service.ts
new file mode 100644
index 000000000..1e890d8f3
--- /dev/null
+++ b/client/src/app/shared/auth/auth-interceptor.service.ts
@@ -0,0 +1,62 @@
+import { Injectable, Injector } from '@angular/core'
+import {
+ HttpInterceptor,
+ HttpRequest,
+ HttpEvent,
+ HttpHandler, HTTP_INTERCEPTORS
+} from '@angular/common/http'
+import { Observable } from 'rxjs/Observable'
+
+import { AuthService } from '../../core'
+import 'rxjs/add/operator/switchMap'
+
+@Injectable()
+export class AuthInterceptor implements HttpInterceptor {
+ private authService: AuthService
+
+ // https://github.com/angular/angular/issues/18224#issuecomment-316957213
+ constructor (private injector: Injector) {}
+
+ intercept (req: HttpRequest, next: HttpHandler): Observable> {
+ if (this.authService === undefined) {
+ this.authService = this.injector.get(AuthService)
+ }
+
+ const authReq = this.cloneRequestWithAuth(req)
+
+ // Pass on the cloned request instead of the original request
+ // Catch 401 errors (refresh token expired)
+ return next.handle(authReq)
+ .catch(err => {
+ if (err.status === 401) {
+ return this.handleTokenExpired(req, next)
+ }
+
+ return Observable.throw(err)
+ })
+ }
+
+ private handleTokenExpired (req: HttpRequest, next: HttpHandler): Observable> {
+ return this.authService.refreshAccessToken()
+ .switchMap(() => {
+ const authReq = this.cloneRequestWithAuth(req)
+
+ return next.handle(authReq)
+ })
+ }
+
+ private cloneRequestWithAuth (req: HttpRequest) {
+ const authHeaderValue = this.authService.getRequestHeaderValue()
+
+ if (authHeaderValue === null) return req
+
+ // Clone the request to add the new header
+ return req.clone({ headers: req.headers.set('Authorization', authHeaderValue) })
+ }
+}
+
+export const AUTH_INTERCEPTOR_PROVIDER = {
+ provide: HTTP_INTERCEPTORS,
+ useClass: AuthInterceptor,
+ multi: true
+}
diff --git a/client/src/app/shared/auth/index.ts b/client/src/app/shared/auth/index.ts
index 0f2bfb0d6..84a07196f 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-interceptor.service'
diff --git a/client/src/app/shared/rest/index.ts b/client/src/app/shared/rest/index.ts
index e0be155cf..3f1996130 100644
--- a/client/src/app/shared/rest/index.ts
+++ b/client/src/app/shared/rest/index.ts
@@ -2,3 +2,4 @@ export * from './rest-data-source'
export * from './rest-extractor.service'
export * from './rest-pagination'
export * from './rest.service'
+export * from './rest-table'
diff --git a/client/src/app/shared/rest/rest-data-source.ts b/client/src/app/shared/rest/rest-data-source.ts
index 5c205d280..57a2efb57 100644
--- a/client/src/app/shared/rest/rest-data-source.ts
+++ b/client/src/app/shared/rest/rest-data-source.ts
@@ -1,68 +1,32 @@
-import { Http, RequestOptionsArgs, URLSearchParams, Response } from '@angular/http'
-
-import { ServerDataSource } from 'ng2-smart-table'
-
-export class RestDataSource extends ServerDataSource {
- private updateResponse: (input: any[]) => any[]
-
- constructor (http: Http, endpoint: string, updateResponse?: (input: any[]) => any[]) {
- const options = {
- endPoint: endpoint,
- sortFieldKey: 'sort',
- dataKey: 'data'
- }
- super(http, options)
-
- if (updateResponse) {
- this.updateResponse = updateResponse
- }
- }
-
- protected extractDataFromResponse (res: Response) {
- const json = res.json()
- if (!json) return []
- let data = json.data
-
- if (this.updateResponse !== undefined) {
- data = this.updateResponse(data)
- }
-
- return data
- }
-
- protected extractTotalFromResponse (res: Response) {
- const rawData = res.json()
- return rawData ? parseInt(rawData.total, 10) : 0
- }
-
- protected addSortRequestOptions (requestOptions: RequestOptionsArgs) {
- const searchParams = requestOptions.params as URLSearchParams
-
- if (this.sortConf) {
- this.sortConf.forEach((fieldConf) => {
- const sortPrefix = fieldConf.direction === 'desc' ? '-' : ''
-
- searchParams.set(this.conf.sortFieldKey, sortPrefix + fieldConf.field)
- })
- }
-
- return requestOptions
- }
-
- protected addPagerRequestOptions (requestOptions: RequestOptionsArgs) {
- const searchParams = requestOptions.params as URLSearchParams
-
- if (this.pagingConf && this.pagingConf['page'] && this.pagingConf['perPage']) {
- const perPage = this.pagingConf['perPage']
- const page = this.pagingConf['page']
-
- const start = (page - 1) * perPage
- const count = perPage
-
- searchParams.set('start', start.toString())
- searchParams.set('count', count.toString())
- }
-
- return requestOptions
- }
+export class RestDataSource {
+ // protected addSortRequestOptions (requestOptions: RequestOptionsArgs) {
+ // const searchParams = requestOptions.params as URLSearchParams
+ //
+ // if (this.sortConf) {
+ // this.sortConf.forEach((fieldConf) => {
+ // const sortPrefix = fieldConf.direction === 'desc' ? '-' : ''
+ //
+ // searchParams.set(this.conf.sortFieldKey, sortPrefix + fieldConf.field)
+ // })
+ // }
+ //
+ // return requestOptions
+ // }
+ //
+ // protected addPagerRequestOptions (requestOptions: RequestOptionsArgs) {
+ // const searchParams = requestOptions.params as URLSearchParams
+ //
+ // if (this.pagingConf && this.pagingConf['page'] && this.pagingConf['perPage']) {
+ // const perPage = this.pagingConf['perPage']
+ // const page = this.pagingConf['page']
+ //
+ // const start = (page - 1) * perPage
+ // const count = perPage
+ //
+ // searchParams.set('start', start.toString())
+ // searchParams.set('count', count.toString())
+ // }
+ //
+ // return requestOptions
+ // }
}
diff --git a/client/src/app/shared/rest/rest-extractor.service.ts b/client/src/app/shared/rest/rest-extractor.service.ts
index f6a818ec8..32dad5c73 100644
--- a/client/src/app/shared/rest/rest-extractor.service.ts
+++ b/client/src/app/shared/rest/rest-extractor.service.ts
@@ -1,52 +1,58 @@
import { Injectable } from '@angular/core'
-import { Response } from '@angular/http'
import { Observable } from 'rxjs/Observable'
+import { HttpErrorResponse } from '@angular/common/http'
-export interface ResultList {
- data: any[]
- total: number
-}
+import { Utils } from '../utils'
+import { ResultList } from '../../../../../shared'
@Injectable()
export class RestExtractor {
- extractDataBool (res: Response) {
+ extractDataBool () {
return true
}
- extractDataList (res: Response) {
- const body = res.json()
+ applyToResultListData (result: ResultList, fun: Function, additionalArgs?: any[]): ResultList {
+ const data: T[] = result.data
+ const newData: T[] = []
- const ret: ResultList = {
- data: body.data,
- total: body.total
+ data.forEach(d => newData.push(fun.call(this, d, additionalArgs)))
+
+ return {
+ total: result.total,
+ data: newData
}
-
- return ret
}
- extractDataGet (res: Response) {
- return res.json()
+ convertResultListDateToHuman (result: ResultList, fieldsToConvert: string[] = [ 'createdAt' ]): ResultList {
+ return this.applyToResultListData(result, this.convertDateToHuman, [ fieldsToConvert ])
}
- handleError (res: Response) {
- let text = 'Server error: '
- text += res.text()
- let json = ''
+ convertDateToHuman (target: object, fieldsToConvert: string[]) {
+ const source = {}
+ fieldsToConvert.forEach(field => {
+ source[field] = Utils.dateToHuman(target[field])
+ })
- try {
- json = res.json()
- } catch (err) {
- console.error('Cannot get JSON from response.')
+ return Object.assign(target, source)
+ }
+
+ handleError (err: HttpErrorResponse) {
+ let errorMessage
+
+ if (err.error instanceof Error) {
+ // A client-side or network error occurred. Handle it accordingly.
+ errorMessage = err.error.message
+ console.error('An error occurred:', errorMessage)
+ } else if (err.status !== undefined) {
+ // The backend returned an unsuccessful response code.
+ // The response body may contain clues as to what went wrong,
+ errorMessage = err.error
+ console.error(`Backend returned code ${err.status}, body was: ${errorMessage}`)
+ } else {
+ errorMessage = err
}
- const error = {
- json,
- text
- }
-
- console.error(error)
-
- return Observable.throw(error)
+ return Observable.throw(errorMessage)
}
}
diff --git a/client/src/app/shared/rest/rest-pagination.ts b/client/src/app/shared/rest/rest-pagination.ts
index 766e7a9e5..0faa59303 100644
--- a/client/src/app/shared/rest/rest-pagination.ts
+++ b/client/src/app/shared/rest/rest-pagination.ts
@@ -1,5 +1,4 @@
export interface RestPagination {
- currentPage: number
- itemsPerPage: number
- totalItems: number
+ start: number
+ count: number
}
diff --git a/client/src/app/shared/rest/rest-table.ts b/client/src/app/shared/rest/rest-table.ts
new file mode 100644
index 000000000..db2cb5e14
--- /dev/null
+++ b/client/src/app/shared/rest/rest-table.ts
@@ -0,0 +1,27 @@
+import { LazyLoadEvent, SortMeta } from 'primeng/primeng'
+
+import { RestPagination } from './rest-pagination'
+
+export abstract class RestTable {
+ abstract totalRecords: number
+ abstract rowsPerPage: number
+ abstract sort: SortMeta
+ abstract pagination: RestPagination
+
+ protected abstract loadData (): void
+
+ loadLazy (event: LazyLoadEvent) {
+ this.sort = {
+ order: event.sortOrder,
+ field: event.sortField
+ }
+
+ this.pagination = {
+ start: event.first,
+ count: this.rowsPerPage
+ }
+
+ this.loadData()
+ }
+
+}
diff --git a/client/src/app/shared/rest/rest.service.ts b/client/src/app/shared/rest/rest.service.ts
index 43dc20b34..f7838ba06 100644
--- a/client/src/app/shared/rest/rest.service.ts
+++ b/client/src/app/shared/rest/rest.service.ts
@@ -1,27 +1,34 @@
import { Injectable } from '@angular/core'
-import { URLSearchParams } from '@angular/http'
+import { HttpParams } from '@angular/common/http'
+import { SortMeta } from 'primeng/primeng'
import { RestPagination } from './rest-pagination'
@Injectable()
export class RestService {
- buildRestGetParams (pagination?: RestPagination, sort?: string) {
- const params = new URLSearchParams()
+ addRestGetParams (params: HttpParams, pagination?: RestPagination, sort?: SortMeta | string) {
+ let newParams = params
- if (pagination) {
- const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage
- const count: number = pagination.itemsPerPage
-
- params.set('start', start.toString())
- params.set('count', count.toString())
+ if (pagination !== undefined) {
+ newParams = newParams.set('start', pagination.start.toString())
+ .set('count', pagination.count.toString())
}
- if (sort) {
- params.set('sort', sort)
+ if (sort !== undefined) {
+ let sortString = ''
+
+ if (typeof sort === 'string') {
+ sortString = sort
+ } else {
+ const sortPrefix = sort.order === 1 ? '' : '-'
+ sortString = sortPrefix + sort.field
+ }
+
+ newParams = newParams.set('sort', sortString)
}
- return params
+ return newParams
}
}
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index 99b51aa4e..118ce822d 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -1,6 +1,6 @@
import { NgModule } from '@angular/core'
+import { HttpClientModule } from '@angular/common/http'
import { CommonModule } from '@angular/common'
-import { HttpModule } from '@angular/http'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterModule } from '@angular/router'
@@ -11,9 +11,9 @@ import { ProgressbarModule } from 'ngx-bootstrap/progressbar'
import { PaginationModule } from 'ngx-bootstrap/pagination'
import { ModalModule } from 'ngx-bootstrap/modal'
import { FileUploadModule } from 'ng2-file-upload/ng2-file-upload'
-import { Ng2SmartTableModule } from 'ng2-smart-table'
+import { DataTableModule, SharedModule as PrimeSharedModule } from 'primeng/primeng'
-import { AUTH_HTTP_PROVIDERS } from './auth'
+import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
import { RestExtractor, RestService } from './rest'
import { SearchComponent, SearchService } from './search'
import { UserService } from './users'
@@ -24,8 +24,8 @@ import { VideoAbuseService } from './video-abuse'
CommonModule,
FormsModule,
ReactiveFormsModule,
- HttpModule,
RouterModule,
+ HttpClientModule,
BsDropdownModule.forRoot(),
ModalModule.forRoot(),
@@ -33,7 +33,9 @@ import { VideoAbuseService } from './video-abuse'
ProgressbarModule.forRoot(),
FileUploadModule,
- Ng2SmartTableModule
+
+ DataTableModule,
+ PrimeSharedModule
],
declarations: [
@@ -46,15 +48,16 @@ import { VideoAbuseService } from './video-abuse'
CommonModule,
FormsModule,
ReactiveFormsModule,
- HttpModule,
RouterModule,
+ HttpClientModule,
BsDropdownModule,
FileUploadModule,
ModalModule,
PaginationModule,
ProgressbarModule,
- Ng2SmartTableModule,
+ DataTableModule,
+ PrimeSharedModule,
BytesPipe,
KeysPipe,
@@ -62,7 +65,7 @@ import { VideoAbuseService } from './video-abuse'
],
providers: [
- AUTH_HTTP_PROVIDERS,
+ AUTH_INTERCEPTOR_PROVIDER,
RestExtractor,
RestService,
SearchService,
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts
index 35180be4d..5c089d221 100644
--- a/client/src/app/shared/users/user.service.ts
+++ b/client/src/app/shared/users/user.service.ts
@@ -1,10 +1,8 @@
import { Injectable } from '@angular/core'
-import { Http } from '@angular/http'
+import { HttpClient } from '@angular/common/http'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/map'
-import { AuthService } from '../../core'
-import { AuthHttp } from '../auth'
import { RestExtractor } from '../rest'
import { UserCreate, UserUpdateMe } from '../../../../../shared'
@@ -13,9 +11,7 @@ export class UserService {
static BASE_USERS_URL = API_URL + '/api/v1/users/'
constructor (
- private http: Http,
- private authHttp: AuthHttp,
- private authService: AuthService,
+ private authHttp: HttpClient,
private restExtractor: RestExtractor
) {}
@@ -34,7 +30,7 @@ export class UserService {
return this.authHttp.put(url, body)
.map(this.restExtractor.extractDataBool)
- .catch((res) => this.restExtractor.handleError(res))
+ .catch(res => this.restExtractor.handleError(res))
}
updateMyDetails (details: UserUpdateMe) {
@@ -42,12 +38,12 @@ export class UserService {
return this.authHttp.put(url, details)
.map(this.restExtractor.extractDataBool)
- .catch((res) => this.restExtractor.handleError(res))
+ .catch(res => this.restExtractor.handleError(res))
}
signup (userCreate: UserCreate) {
- return this.http.post(UserService.BASE_USERS_URL + 'register', userCreate)
+ return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
.map(this.restExtractor.extractDataBool)
- .catch(this.restExtractor.handleError)
+ .catch(res => this.restExtractor.handleError(res))
}
}
diff --git a/client/src/app/shared/utils.ts b/client/src/app/shared/utils.ts
index c3189a570..7c8ae2e3e 100644
--- a/client/src/app/shared/utils.ts
+++ b/client/src/app/shared/utils.ts
@@ -2,15 +2,7 @@ import { DatePipe } from '@angular/common'
export class Utils {
- static dateToHuman (date: String) {
+ static dateToHuman (date: Date) {
return new DatePipe('en').transform(date, 'medium')
}
-
- static getRowDeleteButton () {
- return ''
- }
-
- static getRowEditButton () {
- return ''
- }
}
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 636a02084..984581114 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,53 @@
import { Injectable } from '@angular/core'
-import { Http } from '@angular/http'
-import { Observable } from 'rxjs/Observable'
+import { HttpClient, HttpParams } from '@angular/common/http'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/map'
+import { Observable } from 'rxjs/Observable'
+
+import { SortMeta } from 'primeng/primeng'
import { AuthService } from '../core'
-import { AuthHttp } from '../auth'
-import { RestDataSource, RestExtractor, ResultList } from '../rest'
-import { VideoAbuse } from '../../../../../shared'
+import { RestExtractor, RestPagination, RestService } from '../rest'
+import { Utils } from '../utils'
+import { ResultList, VideoAbuse } from '../../../../../shared'
@Injectable()
export class VideoAbuseService {
private static BASE_VIDEO_ABUSE_URL = API_URL + '/api/v1/videos/'
constructor (
- private authHttp: AuthHttp,
+ private authHttp: HttpClient,
+ private restService: RestService,
private restExtractor: RestExtractor
) {}
- getDataSource () {
- return new RestDataSource(this.authHttp, VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse')
+ getVideoAbuses (pagination: RestPagination, sort: SortMeta): Observable> {
+ const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse'
+
+ let params = new HttpParams()
+ params = this.restService.addRestGetParams(params, pagination, sort)
+
+ return this.authHttp.get>(url, { params })
+ .map(res => this.restExtractor.convertResultListDateToHuman(res))
+ .map(res => this.restExtractor.applyToResultListData(res, this.formatVideoAbuse.bind(this)))
+ .catch(res => this.restExtractor.handleError(res))
}
reportVideo (id: number, reason: string) {
+ const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse'
const body = {
reason
}
- const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse'
return this.authHttp.post(url, body)
.map(this.restExtractor.extractDataBool)
- .catch((res) => this.restExtractor.handleError(res))
+ .catch(res => this.restExtractor.handleError(res))
}
- private extractVideoAbuses (result: ResultList) {
- const videoAbuses: VideoAbuse[] = result.data
- const totalVideoAbuses = result.total
-
- return { videoAbuses, totalVideoAbuses }
+ private formatVideoAbuse (videoAbuse: VideoAbuse) {
+ return Object.assign(videoAbuse, {
+ createdAt: Utils.dateToHuman(videoAbuse.createdAt)
+ })
}
+
}
diff --git a/client/src/app/videos/shared/index.ts b/client/src/app/videos/shared/index.ts
index 97d795321..8168e3bfd 100644
--- a/client/src/app/videos/shared/index.ts
+++ b/client/src/app/videos/shared/index.ts
@@ -1,3 +1,4 @@
export * from './sort-field.type'
export * from './video.model'
export * from './video.service'
+export * from './video-pagination.model'
diff --git a/client/src/app/videos/shared/video-pagination.model.ts b/client/src/app/videos/shared/video-pagination.model.ts
new file mode 100644
index 000000000..9e71769cb
--- /dev/null
+++ b/client/src/app/videos/shared/video-pagination.model.ts
@@ -0,0 +1,5 @@
+export interface VideoPagination {
+ currentPage: number
+ itemsPerPage: number
+ totalItems: number
+}
diff --git a/client/src/app/videos/shared/video.model.ts b/client/src/app/videos/shared/video.model.ts
index 1a413db9d..17f41059d 100644
--- a/client/src/app/videos/shared/video.model.ts
+++ b/client/src/app/videos/shared/video.model.ts
@@ -46,7 +46,7 @@ export class Video implements VideoServerModel {
constructor (hash: {
author: string,
- createdAt: string,
+ createdAt: Date | string,
categoryLabel: string,
category: number,
licenceLabel: string,
@@ -70,7 +70,7 @@ export class Video implements VideoServerModel {
files: VideoFile[]
}) {
this.author = hash.author
- this.createdAt = new Date(hash.createdAt)
+ this.createdAt = new Date(hash.createdAt.toString())
this.categoryLabel = hash.categoryLabel
this.category = hash.category
this.licenceLabel = hash.licenceLabel
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts
index 67091a8d8..b6d2a0666 100644
--- a/client/src/app/videos/shared/video.service.ts
+++ b/client/src/app/videos/shared/video.service.ts
@@ -1,27 +1,26 @@
import { Injectable } from '@angular/core'
-import { Http, Headers, RequestOptions } from '@angular/http'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/map'
+import { HttpClient, HttpParams } from '@angular/common/http'
import { Search } from '../../shared'
import { SortField } from './sort-field.type'
-import { AuthService } from '../../core'
import {
- AuthHttp,
RestExtractor,
- RestPagination,
RestService,
- ResultList,
UserService
} from '../../shared'
import { Video } from './video.model'
+import { VideoPagination } from './video-pagination.model'
import {
- UserVideoRate,
- VideoRateType,
- VideoUpdate,
- VideoAbuseCreate,
- UserVideoRateUpdate
+UserVideoRate,
+VideoRateType,
+VideoUpdate,
+VideoAbuseCreate,
+UserVideoRateUpdate,
+Video as VideoServerModel,
+ResultList
} from '../../../../../shared'
@Injectable()
@@ -33,9 +32,7 @@ export class VideoService {
videoLanguages: Array<{ id: number, label: string }> = []
constructor (
- private authService: AuthService,
- private authHttp: AuthHttp,
- private http: Http,
+ private authHttp: HttpClient,
private restExtractor: RestExtractor,
private restService: RestService
) {}
@@ -52,11 +49,10 @@ export class VideoService {
return this.loadVideoAttributeEnum('languages', this.videoLanguages)
}
- getVideo (uuid: string): Observable