Move to HttpClient and PrimeNG data table
This commit is contained in:
parent
91f6f169b1
commit
d592e0a9b2
|
@ -62,7 +62,6 @@
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"ng-router-loader": "^2.0.0",
|
"ng-router-loader": "^2.0.0",
|
||||||
"ng2-file-upload": "^1.1.4-2",
|
"ng2-file-upload": "^1.1.4-2",
|
||||||
"ng2-smart-table": "1.2.1",
|
|
||||||
"ngc-webpack": "3.2.2",
|
"ngc-webpack": "3.2.2",
|
||||||
"ngx-bootstrap": "1.9.1",
|
"ngx-bootstrap": "1.9.1",
|
||||||
"ngx-chips": "1.5.3",
|
"ngx-chips": "1.5.3",
|
||||||
|
@ -97,6 +96,7 @@
|
||||||
"add-asset-html-webpack-plugin": "^2.0.1",
|
"add-asset-html-webpack-plugin": "^2.0.1",
|
||||||
"codelyzer": "^3.0.0-beta.4",
|
"codelyzer": "^3.0.0-beta.4",
|
||||||
"extract-text-webpack-plugin": "^3.0.0",
|
"extract-text-webpack-plugin": "^3.0.0",
|
||||||
|
"primeng": "^4.2.0",
|
||||||
"purify-css": "^1.2.5",
|
"purify-css": "^1.2.5",
|
||||||
"purifycss-webpack": "^0.7.0",
|
"purifycss-webpack": "^0.7.0",
|
||||||
"standard": "^10.0.0",
|
"standard": "^10.0.0",
|
||||||
|
|
|
@ -93,8 +93,9 @@ export class FriendAddComponent implements OnInit {
|
||||||
|
|
||||||
this.friendService.makeFriends(notEmptyHosts).subscribe(
|
this.friendService.makeFriends(notEmptyHosts).subscribe(
|
||||||
status => {
|
status => {
|
||||||
this.notificationsService.success('Sucess', 'Make friends request sent!')
|
this.notificationsService.success('Success', 'Make friends request sent!')
|
||||||
this.router.navigate([ '/admin/friends/list' ])
|
// Wait requests between pods
|
||||||
|
setTimeout(() => this.router.navigate([ '/admin/friends/list' ]), 1000)
|
||||||
},
|
},
|
||||||
|
|
||||||
err => this.notificationsService.error('Error', err.text)
|
err => this.notificationsService.error('Error', err.text)
|
||||||
|
|
|
@ -2,13 +2,24 @@
|
||||||
<div class="content-padding">
|
<div class="content-padding">
|
||||||
<h3>Friends list</h3>
|
<h3>Friends list</h3>
|
||||||
|
|
||||||
<ng2-smart-table [settings]="tableSettings" [source]="friendsSource" (delete)="removeFriend($event)"></ng2-smart-table>
|
<p-dataTable [value]="friends">
|
||||||
|
<p-column field="id" header="ID"></p-column>
|
||||||
|
<p-column field="host" header="Host"></p-column>
|
||||||
|
<p-column field="email" header="Email"></p-column>
|
||||||
|
<p-column field="score" header="Score"></p-column>
|
||||||
|
<p-column field="createdAt" header="Created date"></p-column>
|
||||||
|
<p-column header="Delete" styleClass="action-cell">
|
||||||
|
<ng-template pTemplate="body" let-pod="rowData">
|
||||||
|
<span (click)="removeFriend(pod)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this pod"></span>
|
||||||
|
</ng-template>
|
||||||
|
</p-column>
|
||||||
|
</p-dataTable>
|
||||||
|
|
||||||
<a *ngIf="hasFriends()" class="btn btn-danger pull-left" (click)="quitFriends()">
|
<a *ngIf="hasFriends()" class="btn btn-danger pull-left" (click)="quitFriends()">
|
||||||
Quit friends
|
Quit friends
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a *ngIf="!hasFriends()" class="btn btn-success pull-right" [routerLink]="['/admin/friends/add']">
|
<a *ngIf="!hasFriends()" class="btn btn-success pull-right" [routerLink]="[ '/admin/friends/add' ]">
|
||||||
Make friends
|
Make friends
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,71 +1,31 @@
|
||||||
import { Component } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
|
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { ServerDataSource } from 'ng2-smart-table'
|
|
||||||
|
|
||||||
import { ConfirmService } from '../../../core'
|
import { ConfirmService } from '../../../core'
|
||||||
import { Utils } from '../../../shared'
|
|
||||||
import { FriendService } from '../shared'
|
import { FriendService } from '../shared'
|
||||||
import { Pod } from '../../../../../../shared'
|
import { Pod } from '../../../../../../shared'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-friend-list',
|
selector: 'my-friend-list',
|
||||||
templateUrl: './friend-list.component.html',
|
templateUrl: './friend-list.component.html',
|
||||||
styleUrls: [ './friend-list.component.scss' ]
|
styleUrls: ['./friend-list.component.scss']
|
||||||
})
|
})
|
||||||
export class FriendListComponent {
|
export class FriendListComponent implements OnInit {
|
||||||
friendsSource = null
|
friends: Pod[] = []
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
private friendService: FriendService
|
private friendService: FriendService
|
||||||
) {
|
) {}
|
||||||
this.friendsSource = this.friendService.getDataSource()
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
hasFriends () {
|
hasFriends () {
|
||||||
return this.friendsSource.count() !== 0
|
return this.friends.length !== 0
|
||||||
}
|
}
|
||||||
|
|
||||||
quitFriends () {
|
quitFriends () {
|
||||||
|
@ -77,32 +37,42 @@ export class FriendListComponent {
|
||||||
this.friendService.quitFriends().subscribe(
|
this.friendService.quitFriends().subscribe(
|
||||||
status => {
|
status => {
|
||||||
this.notificationsService.success('Success', 'Friends left!')
|
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 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(
|
this.confirmService.confirm(confirmMessage, 'Remove').subscribe(
|
||||||
res => {
|
res => {
|
||||||
if (res === false) return
|
if (res === false) return
|
||||||
|
|
||||||
this.friendService.removeFriend(friend).subscribe(
|
this.friendService.removeFriend(friend).subscribe(
|
||||||
status => {
|
status => {
|
||||||
this.notificationsService.success('Success', 'Friend removed')
|
this.notificationsService.success('Success', 'Friend removed')
|
||||||
this.friendsSource.refresh()
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { Injectable } from '@angular/core'
|
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/catch'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
|
|
||||||
import { ServerDataSource } from 'ng2-smart-table'
|
import { RestExtractor, } from '../../../shared'
|
||||||
|
import { Pod, ResultList } from '../../../../../../shared'
|
||||||
import { AuthHttp, RestExtractor, RestDataSource, ResultList } from '../../../shared'
|
|
||||||
import { Pod } from '../../../../../../shared'
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FriendService {
|
export class FriendService {
|
||||||
private static BASE_FRIEND_URL = API_URL + '/api/v1/pods/'
|
private static BASE_FRIEND_URL = API_URL + '/api/v1/pods/'
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: AuthHttp,
|
private authHttp: HttpClient,
|
||||||
private restExtractor: RestExtractor
|
private restExtractor: RestExtractor
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getDataSource () {
|
getFriends () {
|
||||||
return new RestDataSource(this.authHttp, FriendService.BASE_FRIEND_URL)
|
return this.authHttp.get<ResultList<Pod>>(FriendService.BASE_FRIEND_URL)
|
||||||
|
.map(res => this.restExtractor.convertResultListDateToHuman(res))
|
||||||
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
makeFriends (notEmptyHosts: String[]) {
|
makeFriends (notEmptyHosts: String[]) {
|
||||||
|
@ -28,18 +28,18 @@ export class FriendService {
|
||||||
|
|
||||||
return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'make-friends', body)
|
return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'make-friends', body)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
quitFriends () {
|
quitFriends () {
|
||||||
return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quit-friends')
|
return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quit-friends')
|
||||||
.map(res => res.status)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFriend (friend: Pod) {
|
removeFriend (friend: Pod) {
|
||||||
return this.authHttp.delete(FriendService.BASE_FRIEND_URL + friend.id)
|
return this.authHttp.delete(FriendService.BASE_FRIEND_URL + friend.id)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
|
import { HttpClient } from '@angular/common/http'
|
||||||
import { Observable } from 'rxjs/Observable'
|
import { Observable } from 'rxjs/Observable'
|
||||||
import 'rxjs/add/operator/catch'
|
import 'rxjs/add/operator/catch'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
|
|
||||||
import { RequestSchedulerStats } from '../../../../../../shared'
|
import { RequestSchedulerStats } from '../../../../../../shared'
|
||||||
import { AuthHttp, RestExtractor } from '../../../shared'
|
import { RestExtractor } from '../../../shared'
|
||||||
import { RequestSchedulerStatsAttributes } from './request-schedulers-stats-attributes.model'
|
import { RequestSchedulerStatsAttributes } from './request-schedulers-stats-attributes.model'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -12,19 +13,18 @@ export class RequestSchedulersService {
|
||||||
private static BASE_REQUEST_URL = API_URL + '/api/v1/request-schedulers/'
|
private static BASE_REQUEST_URL = API_URL + '/api/v1/request-schedulers/'
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: AuthHttp,
|
private authHttp: HttpClient,
|
||||||
private restExtractor: RestExtractor
|
private restExtractor: RestExtractor
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getStats (): Observable<RequestSchedulerStats> {
|
getStats () {
|
||||||
return this.authHttp.get(RequestSchedulersService.BASE_REQUEST_URL + 'stats')
|
return this.authHttp.get<RequestSchedulerStats>(RequestSchedulersService.BASE_REQUEST_URL + 'stats')
|
||||||
.map(this.restExtractor.extractDataGet)
|
.map(res => this.buildRequestObjects(res))
|
||||||
.map(this.buildRequestObjects)
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildRequestObjects (data: RequestSchedulerStats) {
|
private buildRequestObjects (data: RequestSchedulerStats) {
|
||||||
const requestSchedulers = {}
|
const requestSchedulers: { [ id: string ]: RequestSchedulerStatsAttributes } = {}
|
||||||
|
|
||||||
Object.keys(data).forEach(requestSchedulerName => {
|
Object.keys(data).forEach(requestSchedulerName => {
|
||||||
requestSchedulers[requestSchedulerName] = new RequestSchedulerStatsAttributes(data[requestSchedulerName])
|
requestSchedulers[requestSchedulerName] = new RequestSchedulerStatsAttributes(data[requestSchedulerName])
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { Injectable } from '@angular/core'
|
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/catch'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
|
|
||||||
|
import { SortMeta } from 'primeng/primeng'
|
||||||
import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'
|
import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'
|
||||||
|
|
||||||
import { AuthHttp, RestExtractor, RestDataSource, User } from '../../../shared'
|
import { RestExtractor, User, RestPagination, RestService } from '../../../shared'
|
||||||
import { UserCreate, UserUpdate } from '../../../../../../shared'
|
import { UserCreate, UserUpdate, ResultList } from '../../../../../../shared'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserService {
|
export class UserService {
|
||||||
|
@ -13,53 +16,52 @@ export class UserService {
|
||||||
private bytesPipe = new BytesPipe()
|
private bytesPipe = new BytesPipe()
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: AuthHttp,
|
private authHttp: HttpClient,
|
||||||
|
private restService: RestService,
|
||||||
private restExtractor: RestExtractor
|
private restExtractor: RestExtractor
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
addUser (userCreate: UserCreate) {
|
addUser (userCreate: UserCreate) {
|
||||||
return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
|
return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch(this.restExtractor.handleError)
|
.catch(err => this.restExtractor.handleError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUser (userId: number, userUpdate: UserUpdate) {
|
updateUser (userId: number, userUpdate: UserUpdate) {
|
||||||
return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
|
return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch(this.restExtractor.handleError)
|
.catch(err => this.restExtractor.handleError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
getUser (userId: number) {
|
getUser (userId: number) {
|
||||||
return this.authHttp.get(UserService.BASE_USERS_URL + userId)
|
return this.authHttp.get<User>(UserService.BASE_USERS_URL + userId)
|
||||||
.map(this.restExtractor.extractDataGet)
|
.catch(err => this.restExtractor.handleError(err))
|
||||||
.catch(this.restExtractor.handleError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataSource () {
|
getUsers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<User>> {
|
||||||
return new RestDataSource(this.authHttp, UserService.BASE_USERS_URL, this.formatDataSource.bind(this))
|
let params = new HttpParams()
|
||||||
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
|
|
||||||
|
return this.authHttp.get<ResultList<User>>(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) {
|
removeUser (user: User) {
|
||||||
return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
|
return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatDataSource (users: User[]) {
|
private formatUser (user: User) {
|
||||||
const newUsers = []
|
let videoQuota
|
||||||
|
if (user.videoQuota === -1) {
|
||||||
|
videoQuota = 'Unlimited'
|
||||||
|
} else {
|
||||||
|
videoQuota = this.bytesPipe.transform(user.videoQuota)
|
||||||
|
}
|
||||||
|
|
||||||
users.forEach(user => {
|
return Object.assign(user, {
|
||||||
let videoQuota
|
videoQuota
|
||||||
if (user.videoQuota === -1) {
|
|
||||||
videoQuota = 'Unlimited'
|
|
||||||
} else {
|
|
||||||
videoQuota = this.bytesPipe.transform(user.videoQuota)
|
|
||||||
}
|
|
||||||
|
|
||||||
const newUser = Object.assign(user, {
|
|
||||||
videoQuota
|
|
||||||
})
|
|
||||||
newUsers.push(newUser)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return newUsers
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,29 @@
|
||||||
|
|
||||||
<h3>Users list</h3>
|
<h3>Users list</h3>
|
||||||
|
|
||||||
<ng2-smart-table
|
<p-dataTable
|
||||||
[settings]="tableSettings" [source]="usersSource"
|
[value]="users" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
||||||
(delete)="removeUser($event)" (edit)="editUser($event)"
|
sortField="id" (onLazyLoad)="loadLazy($event)"
|
||||||
></ng2-smart-table>
|
>
|
||||||
|
<p-column field="id" header="ID" [sortable]="true"></p-column>
|
||||||
|
<p-column field="username" header="Username" [sortable]="true"></p-column>
|
||||||
|
<p-column field="email" header="Email"></p-column>
|
||||||
|
<p-column field="videoQuota" header="Video quota"></p-column>
|
||||||
|
<p-column field="role" header="Role"></p-column>
|
||||||
|
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
|
||||||
|
<p-column header="Edit" styleClass="action-cell">
|
||||||
|
<ng-template pTemplate="body" let-user="rowData">
|
||||||
|
<a [routerLink]="getRouterUserEditLink(user)" title="Edit this user">
|
||||||
|
<span class="glyphicon glyphicon-pencil glyphicon-black"></span>
|
||||||
|
</a>
|
||||||
|
</ng-template>
|
||||||
|
</p-column>
|
||||||
|
<p-column header="Delete" styleClass="action-cell">
|
||||||
|
<ng-template pTemplate="body" let-user="rowData">
|
||||||
|
<span (click)="removeUser(user)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this user"></span>
|
||||||
|
</ng-template>
|
||||||
|
</p-column>
|
||||||
|
</p-dataTable>
|
||||||
|
|
||||||
<a class="add-user btn btn-success pull-right" [routerLink]="['/admin/users/add']">
|
<a class="add-user btn btn-success pull-right" [routerLink]="['/admin/users/add']">
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
|
|
|
@ -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 { NotificationsService } from 'angular2-notifications'
|
||||||
|
|
||||||
import { ConfirmService } from '../../../core'
|
import { ConfirmService } from '../../../core'
|
||||||
import { RestDataSource, User, Utils } from '../../../shared'
|
import { RestTable, RestPagination, User } from '../../../shared'
|
||||||
import { UserService } from '../shared'
|
import { UserService } from '../shared'
|
||||||
import { Router } from '@angular/router'
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-user-list',
|
selector: 'my-user-list',
|
||||||
templateUrl: './user-list.component.html',
|
templateUrl: './user-list.component.html',
|
||||||
styleUrls: [ './user-list.component.scss' ]
|
styleUrls: [ './user-list.component.scss' ]
|
||||||
})
|
})
|
||||||
export class UserListComponent {
|
export class UserListComponent extends RestTable implements OnInit {
|
||||||
usersSource: RestDataSource = null
|
users: User[] = []
|
||||||
tableSettings = {
|
totalRecords = 0
|
||||||
mode: 'external',
|
rowsPerPage = 10
|
||||||
attr: {
|
sort: SortMeta = { field: 'id', order: 1 }
|
||||||
class: 'table-hover'
|
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||||
},
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private router: Router,
|
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
private userService: UserService
|
private userService: UserService
|
||||||
) {
|
) {
|
||||||
this.usersSource = this.userService.getDataSource()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
editUser ({ data }: { data: User }) {
|
ngOnInit () {
|
||||||
this.router.navigate([ '/admin', 'users', data.id, 'update' ])
|
this.loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUser ({ data }: { data: User }) {
|
removeUser (user: User) {
|
||||||
const user = data
|
|
||||||
|
|
||||||
if (user.username === 'root') {
|
if (user.username === 'root') {
|
||||||
this.notificationsService.error('Error', 'You cannot delete root.')
|
this.notificationsService.error('Error', 'You cannot delete root.')
|
||||||
return
|
return
|
||||||
|
@ -89,12 +44,28 @@ export class UserListComponent {
|
||||||
this.userService.removeUser(user).subscribe(
|
this.userService.removeUser(user).subscribe(
|
||||||
() => {
|
() => {
|
||||||
this.notificationsService.success('Success', `User ${user.username} deleted.`)
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,21 @@
|
||||||
|
|
||||||
<h3>Video abuses list</h3>
|
<h3>Video abuses list</h3>
|
||||||
|
|
||||||
<ng2-smart-table
|
<p-dataTable
|
||||||
[settings]="tableSettings" [source]="videoAbusesSource"
|
[value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
||||||
></ng2-smart-table>
|
sortField="id" (onLazyLoad)="loadLazy($event)"
|
||||||
|
>
|
||||||
|
<p-column field="id" header="ID" [sortable]="true"></p-column>
|
||||||
|
<p-column field="reason" header="Reason"></p-column>
|
||||||
|
<p-column field="reporterPodHost" header="Reporter pod host"></p-column>
|
||||||
|
<p-column field="reporterUsername" header="Reporter username"></p-column>
|
||||||
|
<p-column header="Video" styleClass="action-cell">
|
||||||
|
<ng-template pTemplate="body" let-videoAbuse="rowData">
|
||||||
|
<a [routerLink]="getRouterVideoLink(videoAbuse.videoId)" title="Go to the video">{{ videoAbuse.videoId }}</a>
|
||||||
|
</ng-template>
|
||||||
|
</p-column>
|
||||||
|
<p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
|
||||||
|
</p-dataTable>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,72 +1,46 @@
|
||||||
import { Component } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
|
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
import { SortMeta } from 'primeng/primeng'
|
||||||
|
|
||||||
import { Utils, VideoAbuseService } from '../../../shared'
|
import { RestTable, RestPagination, VideoAbuseService } from '../../../shared'
|
||||||
import { VideoAbuse } from '../../../../../shared'
|
import { VideoAbuse } from '../../../../../../shared'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-video-abuse-list',
|
selector: 'my-video-abuse-list',
|
||||||
templateUrl: './video-abuse-list.component.html'
|
templateUrl: './video-abuse-list.component.html'
|
||||||
})
|
})
|
||||||
export class VideoAbuseListComponent {
|
export class VideoAbuseListComponent extends RestTable implements OnInit {
|
||||||
videoAbusesSource = null
|
videoAbuses: VideoAbuse[] = []
|
||||||
tableSettings = {
|
totalRecords = 0
|
||||||
mode: 'external',
|
rowsPerPage = 1
|
||||||
attr: {
|
sort: SortMeta = { field: 'id', order: 1 }
|
||||||
class: 'table-hover'
|
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||||
},
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private videoAbuseService: VideoAbuseService
|
private videoAbuseService: VideoAbuseService
|
||||||
) {
|
) {
|
||||||
this.videoAbusesSource = this.videoAbuseService.getDataSource()
|
super()
|
||||||
}
|
}
|
||||||
|
|
||||||
buildVideoLink (videoId: string) {
|
ngOnInit () {
|
||||||
// TODO: transform to routerLink
|
this.loadData()
|
||||||
// https://github.com/akveo/ng2-smart-table/issues/57
|
}
|
||||||
return `<a href="/videos/${videoId}" title="Go to the video">${videoId}</a>`
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ export class AccountDetailsComponent extends FormReactive implements OnInit {
|
||||||
() => {
|
() => {
|
||||||
this.notificationsService.success('Success', 'Information updated.')
|
this.notificationsService.success('Success', 'Information updated.')
|
||||||
|
|
||||||
this.authService.refreshUserInformations()
|
this.authService.refreshUserInformation()
|
||||||
},
|
},
|
||||||
|
|
||||||
err => this.error = err
|
err => this.error = err
|
||||||
|
|
|
@ -36,6 +36,8 @@ export class AppComponent implements OnInit {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
|
this.authService.loadClientCredentials()
|
||||||
|
|
||||||
if (this.authService.isLoggedIn()) {
|
if (this.authService.isLoggedIn()) {
|
||||||
// The service will automatically redirect to the login page if the token is not valid anymore
|
// The service will automatically redirect to the login page if the token is not valid anymore
|
||||||
this.userService.checkTokenValidity()
|
this.userService.checkTokenValidity()
|
||||||
|
|
|
@ -7,8 +7,6 @@ import {
|
||||||
} from '@angularclass/hmr'
|
} from '@angularclass/hmr'
|
||||||
|
|
||||||
import { MetaModule, MetaLoader, MetaStaticLoader, PageTitlePositioning } from '@ngx-meta/core'
|
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 'bootstrap-loader'
|
||||||
|
|
||||||
import { ENV_PROVIDERS } from './environment'
|
import { ENV_PROVIDERS } from './environment'
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Headers, Http, Response, URLSearchParams } from '@angular/http'
|
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
import { Observable } from 'rxjs/Observable'
|
import { Observable } from 'rxjs/Observable'
|
||||||
import { Subject } from 'rxjs/Subject'
|
import { Subject } from 'rxjs/Subject'
|
||||||
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
import 'rxjs/add/operator/mergeMap'
|
import 'rxjs/add/operator/mergeMap'
|
||||||
import 'rxjs/add/observable/throw'
|
import 'rxjs/add/observable/throw'
|
||||||
|
@ -11,15 +11,35 @@ import { NotificationsService } from 'angular2-notifications'
|
||||||
|
|
||||||
import { AuthStatus } from './auth-status.model'
|
import { AuthStatus } from './auth-status.model'
|
||||||
import { AuthUser } from './auth-user.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)
|
// Do not use the barrel (dependency loop)
|
||||||
import { RestExtractor } from '../../shared/rest'
|
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()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
private static BASE_CLIENT_URL = API_URL + '/api/v1/oauth-clients/local'
|
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_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<AuthStatus>
|
loginChangedSource: Observable<AuthStatus>
|
||||||
|
|
||||||
|
@ -29,7 +49,7 @@ export class AuthService {
|
||||||
private user: AuthUser = null
|
private user: AuthUser = null
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private http: Http,
|
private http: HttpClient,
|
||||||
private notificationsService: NotificationsService,
|
private notificationsService: NotificationsService,
|
||||||
private restExtractor: RestExtractor,
|
private restExtractor: RestExtractor,
|
||||||
private router: Router
|
private router: Router
|
||||||
|
@ -37,32 +57,33 @@ export class AuthService {
|
||||||
this.loginChanged = new Subject<AuthStatus>()
|
this.loginChanged = new Subject<AuthStatus>()
|
||||||
this.loginChangedSource = this.loginChanged.asObservable()
|
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
|
// Return null if there is nothing to load
|
||||||
this.user = AuthUser.load()
|
this.user = AuthUser.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadClientCredentials () {
|
||||||
|
// Fetch the client_id/client_secret
|
||||||
|
// FIXME: save in local storage?
|
||||||
|
this.http.get<OAuthClientLocal>(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 () {
|
getRefreshToken () {
|
||||||
if (this.user === null) return null
|
if (this.user === null) return null
|
||||||
|
|
||||||
|
@ -70,7 +91,11 @@ export class AuthService {
|
||||||
}
|
}
|
||||||
|
|
||||||
getRequestHeaderValue () {
|
getRequestHeaderValue () {
|
||||||
return `${this.getTokenType()} ${this.getAccessToken()}`
|
const accessToken = this.getAccessToken()
|
||||||
|
|
||||||
|
if (accessToken === null) return null
|
||||||
|
|
||||||
|
return `${this.getTokenType()} ${accessToken}`
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccessToken () {
|
getAccessToken () {
|
||||||
|
@ -96,39 +121,26 @@ export class AuthService {
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoggedIn () {
|
isLoggedIn () {
|
||||||
if (this.getAccessToken()) {
|
return !!this.getAccessToken()
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
login (username: string, password: string) {
|
login (username: string, password: string) {
|
||||||
let body = new URLSearchParams()
|
// Form url encoded
|
||||||
body.set('client_id', this.clientId)
|
const body = new HttpParams().set('client_id', this.clientId)
|
||||||
body.set('client_secret', this.clientSecret)
|
.set('client_secret', this.clientSecret)
|
||||||
body.set('response_type', 'code')
|
.set('response_type', 'code')
|
||||||
body.set('grant_type', 'password')
|
.set('grant_type', 'password')
|
||||||
body.set('scope', 'upload')
|
.set('scope', 'upload')
|
||||||
body.set('username', username)
|
.set('username', username)
|
||||||
body.set('password', password)
|
.set('password', password)
|
||||||
|
|
||||||
let headers = new Headers()
|
const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
|
||||||
headers.append('Content-Type', 'application/x-www-form-urlencoded')
|
|
||||||
|
|
||||||
let options = {
|
return this.http.post<UserLogin>(AuthService.BASE_TOKEN_URL, body, { headers })
|
||||||
headers: headers
|
.map(res => Object.assign(res, { username }))
|
||||||
}
|
.flatMap(res => this.mergeUserInformation(res))
|
||||||
|
|
||||||
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))
|
|
||||||
.map(res => this.handleLogin(res))
|
.map(res => this.handleLogin(res))
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
logout () {
|
logout () {
|
||||||
|
@ -145,33 +157,26 @@ export class AuthService {
|
||||||
|
|
||||||
const refreshToken = this.getRefreshToken()
|
const refreshToken = this.getRefreshToken()
|
||||||
|
|
||||||
let body = new URLSearchParams()
|
// Form url encoded
|
||||||
body.set('refresh_token', refreshToken)
|
const body = new HttpParams().set('refresh_token', refreshToken)
|
||||||
body.set('client_id', this.clientId)
|
.set('client_id', this.clientId)
|
||||||
body.set('client_secret', this.clientSecret)
|
.set('client_secret', this.clientSecret)
|
||||||
body.set('response_type', 'code')
|
.set('response_type', 'code')
|
||||||
body.set('grant_type', 'refresh_token')
|
.set('grant_type', 'refresh_token')
|
||||||
|
|
||||||
let headers = new Headers()
|
const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
|
||||||
headers.append('Content-Type', 'application/x-www-form-urlencoded')
|
|
||||||
|
|
||||||
let options = {
|
return this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers })
|
||||||
headers: headers
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options)
|
|
||||||
.map(this.restExtractor.extractDataGet)
|
|
||||||
.map(res => this.handleRefreshToken(res))
|
.map(res => this.handleRefreshToken(res))
|
||||||
.catch((res: Response) => {
|
.catch(res => {
|
||||||
// The refresh token is invalid?
|
// 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...')
|
console.error('Cannot refresh token -> logout...')
|
||||||
this.logout()
|
this.logout()
|
||||||
this.router.navigate(['/login'])
|
this.router.navigate(['/login'])
|
||||||
|
|
||||||
return Observable.throw({
|
return Observable.throw({
|
||||||
json: () => '',
|
error: 'You need to reconnect.'
|
||||||
text: () => 'You need to reconnect.'
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +184,7 @@ export class AuthService {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshUserInformations () {
|
refreshUserInformation () {
|
||||||
const obj = {
|
const obj = {
|
||||||
access_token: this.user.getAccessToken(),
|
access_token: this.user.getAccessToken(),
|
||||||
refresh_token: null,
|
refresh_token: null,
|
||||||
|
@ -187,7 +192,7 @@ export class AuthService {
|
||||||
username: this.user.username
|
username: this.user.username
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mergeUserInformations (obj)
|
this.mergeUserInformation(obj)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
res => {
|
res => {
|
||||||
this.user.displayNSFW = res.displayNSFW
|
this.user.displayNSFW = res.displayNSFW
|
||||||
|
@ -198,42 +203,25 @@ export class AuthService {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private mergeUserInformations (obj: {
|
private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> {
|
||||||
access_token: string,
|
// User is not loaded yet, set manually auth header
|
||||||
refresh_token: string,
|
const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`)
|
||||||
token_type: string,
|
|
||||||
username: string
|
|
||||||
}) {
|
|
||||||
// Do not call authHttp here to avoid circular dependencies headaches
|
|
||||||
|
|
||||||
const headers = new Headers()
|
return this.http.get<User>(AuthService.BASE_USER_INFORMATION_URL, { headers })
|
||||||
headers.set('Authorization', `Bearer ${obj.access_token}`)
|
.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 })
|
return Object.assign(obj, newProperties)
|
||||||
.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)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleLogin (obj: {
|
private handleLogin (obj: UserLoginWithUserInformation) {
|
||||||
access_token: string,
|
|
||||||
refresh_token: string,
|
|
||||||
token_type: string,
|
|
||||||
id: number,
|
|
||||||
username: string,
|
|
||||||
email: string,
|
|
||||||
role: UserRole,
|
|
||||||
displayNSFW: boolean
|
|
||||||
}) {
|
|
||||||
const id = obj.id
|
const id = obj.id
|
||||||
const username = obj.username
|
const username = obj.username
|
||||||
const role = obj.role
|
const role = obj.role
|
||||||
|
@ -251,7 +239,7 @@ export class AuthService {
|
||||||
this.setStatus(AuthStatus.LoggedIn)
|
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.refreshTokens(obj.access_token, obj.refresh_token)
|
||||||
this.user.save()
|
this.user.save()
|
||||||
}
|
}
|
||||||
|
@ -259,5 +247,4 @@ export class AuthService {
|
||||||
private setStatus (status: AuthStatus) {
|
private setStatus (status: AuthStatus) {
|
||||||
this.loginChanged.next(status)
|
this.loginChanged.next(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { Injectable } from '@angular/core'
|
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'
|
import { ServerConfig } from '../../../../../shared'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -14,17 +13,11 @@ export class ConfigService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (
|
constructor (private http: HttpClient) {}
|
||||||
private http: Http,
|
|
||||||
private restExtractor: RestExtractor
|
|
||||||
) {}
|
|
||||||
|
|
||||||
loadConfig () {
|
loadConfig () {
|
||||||
this.http.get(ConfigService.BASE_CONFIG_URL)
|
this.http.get<ServerConfig>(ConfigService.BASE_CONFIG_URL)
|
||||||
.map(this.restExtractor.extractDataGet)
|
.subscribe(data => this.config = data)
|
||||||
.subscribe(data => {
|
|
||||||
this.config = data
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfig () {
|
getConfig () {
|
||||||
|
|
|
@ -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<Response> {
|
|
||||||
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<Response> {
|
|
||||||
if (!options) options = {}
|
|
||||||
options.method = RequestMethod.Delete
|
|
||||||
|
|
||||||
return this.request(url, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
get (url: string, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
if (!options) options = {}
|
|
||||||
options.method = RequestMethod.Get
|
|
||||||
|
|
||||||
return this.request(url, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
post (url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
if (!options) options = {}
|
|
||||||
options.method = RequestMethod.Post
|
|
||||||
options.body = body
|
|
||||||
|
|
||||||
return this.request(url, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
put (url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
|
|
||||||
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 ]
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -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<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
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<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
return this.authService.refreshAccessToken()
|
||||||
|
.switchMap(() => {
|
||||||
|
const authReq = this.cloneRequestWithAuth(req)
|
||||||
|
|
||||||
|
return next.handle(authReq)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private cloneRequestWithAuth (req: HttpRequest<any>) {
|
||||||
|
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
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
export * from './auth-http.service'
|
export * from './auth-interceptor.service'
|
||||||
|
|
|
@ -2,3 +2,4 @@ export * from './rest-data-source'
|
||||||
export * from './rest-extractor.service'
|
export * from './rest-extractor.service'
|
||||||
export * from './rest-pagination'
|
export * from './rest-pagination'
|
||||||
export * from './rest.service'
|
export * from './rest.service'
|
||||||
|
export * from './rest-table'
|
||||||
|
|
|
@ -1,68 +1,32 @@
|
||||||
import { Http, RequestOptionsArgs, URLSearchParams, Response } from '@angular/http'
|
export class RestDataSource {
|
||||||
|
// protected addSortRequestOptions (requestOptions: RequestOptionsArgs) {
|
||||||
import { ServerDataSource } from 'ng2-smart-table'
|
// const searchParams = requestOptions.params as URLSearchParams
|
||||||
|
//
|
||||||
export class RestDataSource extends ServerDataSource {
|
// if (this.sortConf) {
|
||||||
private updateResponse: (input: any[]) => any[]
|
// this.sortConf.forEach((fieldConf) => {
|
||||||
|
// const sortPrefix = fieldConf.direction === 'desc' ? '-' : ''
|
||||||
constructor (http: Http, endpoint: string, updateResponse?: (input: any[]) => any[]) {
|
//
|
||||||
const options = {
|
// searchParams.set(this.conf.sortFieldKey, sortPrefix + fieldConf.field)
|
||||||
endPoint: endpoint,
|
// })
|
||||||
sortFieldKey: 'sort',
|
// }
|
||||||
dataKey: 'data'
|
//
|
||||||
}
|
// return requestOptions
|
||||||
super(http, options)
|
// }
|
||||||
|
//
|
||||||
if (updateResponse) {
|
// protected addPagerRequestOptions (requestOptions: RequestOptionsArgs) {
|
||||||
this.updateResponse = updateResponse
|
// const searchParams = requestOptions.params as URLSearchParams
|
||||||
}
|
//
|
||||||
}
|
// if (this.pagingConf && this.pagingConf['page'] && this.pagingConf['perPage']) {
|
||||||
|
// const perPage = this.pagingConf['perPage']
|
||||||
protected extractDataFromResponse (res: Response) {
|
// const page = this.pagingConf['page']
|
||||||
const json = res.json()
|
//
|
||||||
if (!json) return []
|
// const start = (page - 1) * perPage
|
||||||
let data = json.data
|
// const count = perPage
|
||||||
|
//
|
||||||
if (this.updateResponse !== undefined) {
|
// searchParams.set('start', start.toString())
|
||||||
data = this.updateResponse(data)
|
// searchParams.set('count', count.toString())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return data
|
// return requestOptions
|
||||||
}
|
// }
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +1,58 @@
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Response } from '@angular/http'
|
|
||||||
import { Observable } from 'rxjs/Observable'
|
import { Observable } from 'rxjs/Observable'
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http'
|
||||||
|
|
||||||
export interface ResultList {
|
import { Utils } from '../utils'
|
||||||
data: any[]
|
import { ResultList } from '../../../../../shared'
|
||||||
total: number
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RestExtractor {
|
export class RestExtractor {
|
||||||
|
|
||||||
extractDataBool (res: Response) {
|
extractDataBool () {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
extractDataList (res: Response) {
|
applyToResultListData <T> (result: ResultList<T>, fun: Function, additionalArgs?: any[]): ResultList<T> {
|
||||||
const body = res.json()
|
const data: T[] = result.data
|
||||||
|
const newData: T[] = []
|
||||||
|
|
||||||
const ret: ResultList = {
|
data.forEach(d => newData.push(fun.call(this, d, additionalArgs)))
|
||||||
data: body.data,
|
|
||||||
total: body.total
|
return {
|
||||||
|
total: result.total,
|
||||||
|
data: newData
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extractDataGet (res: Response) {
|
convertResultListDateToHuman <T> (result: ResultList<T>, fieldsToConvert: string[] = [ 'createdAt' ]): ResultList<T> {
|
||||||
return res.json()
|
return this.applyToResultListData(result, this.convertDateToHuman, [ fieldsToConvert ])
|
||||||
}
|
}
|
||||||
|
|
||||||
handleError (res: Response) {
|
convertDateToHuman (target: object, fieldsToConvert: string[]) {
|
||||||
let text = 'Server error: '
|
const source = {}
|
||||||
text += res.text()
|
fieldsToConvert.forEach(field => {
|
||||||
let json = ''
|
source[field] = Utils.dateToHuman(target[field])
|
||||||
|
})
|
||||||
|
|
||||||
try {
|
return Object.assign(target, source)
|
||||||
json = res.json()
|
}
|
||||||
} catch (err) {
|
|
||||||
console.error('Cannot get JSON from response.')
|
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 = {
|
return Observable.throw(errorMessage)
|
||||||
json,
|
|
||||||
text
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error(error)
|
|
||||||
|
|
||||||
return Observable.throw(error)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export interface RestPagination {
|
export interface RestPagination {
|
||||||
currentPage: number
|
start: number
|
||||||
itemsPerPage: number
|
count: number
|
||||||
totalItems: number
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,27 +1,34 @@
|
||||||
import { Injectable } from '@angular/core'
|
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'
|
import { RestPagination } from './rest-pagination'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RestService {
|
export class RestService {
|
||||||
|
|
||||||
buildRestGetParams (pagination?: RestPagination, sort?: string) {
|
addRestGetParams (params: HttpParams, pagination?: RestPagination, sort?: SortMeta | string) {
|
||||||
const params = new URLSearchParams()
|
let newParams = params
|
||||||
|
|
||||||
if (pagination) {
|
if (pagination !== undefined) {
|
||||||
const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage
|
newParams = newParams.set('start', pagination.start.toString())
|
||||||
const count: number = pagination.itemsPerPage
|
.set('count', pagination.count.toString())
|
||||||
|
|
||||||
params.set('start', start.toString())
|
|
||||||
params.set('count', count.toString())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sort) {
|
if (sort !== undefined) {
|
||||||
params.set('sort', sort)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
|
import { HttpClientModule } from '@angular/common/http'
|
||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { HttpModule } from '@angular/http'
|
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ import { ProgressbarModule } from 'ngx-bootstrap/progressbar'
|
||||||
import { PaginationModule } from 'ngx-bootstrap/pagination'
|
import { PaginationModule } from 'ngx-bootstrap/pagination'
|
||||||
import { ModalModule } from 'ngx-bootstrap/modal'
|
import { ModalModule } from 'ngx-bootstrap/modal'
|
||||||
import { FileUploadModule } from 'ng2-file-upload/ng2-file-upload'
|
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 { RestExtractor, RestService } from './rest'
|
||||||
import { SearchComponent, SearchService } from './search'
|
import { SearchComponent, SearchService } from './search'
|
||||||
import { UserService } from './users'
|
import { UserService } from './users'
|
||||||
|
@ -24,8 +24,8 @@ import { VideoAbuseService } from './video-abuse'
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
HttpModule,
|
|
||||||
RouterModule,
|
RouterModule,
|
||||||
|
HttpClientModule,
|
||||||
|
|
||||||
BsDropdownModule.forRoot(),
|
BsDropdownModule.forRoot(),
|
||||||
ModalModule.forRoot(),
|
ModalModule.forRoot(),
|
||||||
|
@ -33,7 +33,9 @@ import { VideoAbuseService } from './video-abuse'
|
||||||
ProgressbarModule.forRoot(),
|
ProgressbarModule.forRoot(),
|
||||||
|
|
||||||
FileUploadModule,
|
FileUploadModule,
|
||||||
Ng2SmartTableModule
|
|
||||||
|
DataTableModule,
|
||||||
|
PrimeSharedModule
|
||||||
],
|
],
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -46,15 +48,16 @@ import { VideoAbuseService } from './video-abuse'
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
HttpModule,
|
|
||||||
RouterModule,
|
RouterModule,
|
||||||
|
HttpClientModule,
|
||||||
|
|
||||||
BsDropdownModule,
|
BsDropdownModule,
|
||||||
FileUploadModule,
|
FileUploadModule,
|
||||||
ModalModule,
|
ModalModule,
|
||||||
PaginationModule,
|
PaginationModule,
|
||||||
ProgressbarModule,
|
ProgressbarModule,
|
||||||
Ng2SmartTableModule,
|
DataTableModule,
|
||||||
|
PrimeSharedModule,
|
||||||
BytesPipe,
|
BytesPipe,
|
||||||
KeysPipe,
|
KeysPipe,
|
||||||
|
|
||||||
|
@ -62,7 +65,7 @@ import { VideoAbuseService } from './video-abuse'
|
||||||
],
|
],
|
||||||
|
|
||||||
providers: [
|
providers: [
|
||||||
AUTH_HTTP_PROVIDERS,
|
AUTH_INTERCEPTOR_PROVIDER,
|
||||||
RestExtractor,
|
RestExtractor,
|
||||||
RestService,
|
RestService,
|
||||||
SearchService,
|
SearchService,
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
import { Injectable } from '@angular/core'
|
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/catch'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
|
|
||||||
import { AuthService } from '../../core'
|
|
||||||
import { AuthHttp } from '../auth'
|
|
||||||
import { RestExtractor } from '../rest'
|
import { RestExtractor } from '../rest'
|
||||||
import { UserCreate, UserUpdateMe } from '../../../../../shared'
|
import { UserCreate, UserUpdateMe } from '../../../../../shared'
|
||||||
|
|
||||||
|
@ -13,9 +11,7 @@ export class UserService {
|
||||||
static BASE_USERS_URL = API_URL + '/api/v1/users/'
|
static BASE_USERS_URL = API_URL + '/api/v1/users/'
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private http: Http,
|
private authHttp: HttpClient,
|
||||||
private authHttp: AuthHttp,
|
|
||||||
private authService: AuthService,
|
|
||||||
private restExtractor: RestExtractor
|
private restExtractor: RestExtractor
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -34,7 +30,7 @@ export class UserService {
|
||||||
|
|
||||||
return this.authHttp.put(url, body)
|
return this.authHttp.put(url, body)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMyDetails (details: UserUpdateMe) {
|
updateMyDetails (details: UserUpdateMe) {
|
||||||
|
@ -42,12 +38,12 @@ export class UserService {
|
||||||
|
|
||||||
return this.authHttp.put(url, details)
|
return this.authHttp.put(url, details)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
signup (userCreate: UserCreate) {
|
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)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch(this.restExtractor.handleError)
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,7 @@ import { DatePipe } from '@angular/common'
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
|
|
||||||
static dateToHuman (date: String) {
|
static dateToHuman (date: Date) {
|
||||||
return new DatePipe('en').transform(date, 'medium')
|
return new DatePipe('en').transform(date, 'medium')
|
||||||
}
|
}
|
||||||
|
|
||||||
static getRowDeleteButton () {
|
|
||||||
return '<span class="glyphicon glyphicon-remove glyphicon-black"></span>'
|
|
||||||
}
|
|
||||||
|
|
||||||
static getRowEditButton () {
|
|
||||||
return '<span class="glyphicon glyphicon-pencil glyphicon-black"></span>'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,53 @@
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Http } from '@angular/http'
|
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Observable } from 'rxjs/Observable'
|
|
||||||
import 'rxjs/add/operator/catch'
|
import 'rxjs/add/operator/catch'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
|
import { Observable } from 'rxjs/Observable'
|
||||||
|
|
||||||
|
import { SortMeta } from 'primeng/primeng'
|
||||||
|
|
||||||
import { AuthService } from '../core'
|
import { AuthService } from '../core'
|
||||||
import { AuthHttp } from '../auth'
|
import { RestExtractor, RestPagination, RestService } from '../rest'
|
||||||
import { RestDataSource, RestExtractor, ResultList } from '../rest'
|
import { Utils } from '../utils'
|
||||||
import { VideoAbuse } from '../../../../../shared'
|
import { ResultList, VideoAbuse } from '../../../../../shared'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class VideoAbuseService {
|
export class VideoAbuseService {
|
||||||
private static BASE_VIDEO_ABUSE_URL = API_URL + '/api/v1/videos/'
|
private static BASE_VIDEO_ABUSE_URL = API_URL + '/api/v1/videos/'
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: AuthHttp,
|
private authHttp: HttpClient,
|
||||||
|
private restService: RestService,
|
||||||
private restExtractor: RestExtractor
|
private restExtractor: RestExtractor
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getDataSource () {
|
getVideoAbuses (pagination: RestPagination, sort: SortMeta): Observable<ResultList<VideoAbuse>> {
|
||||||
return new RestDataSource(this.authHttp, VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse')
|
const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse'
|
||||||
|
|
||||||
|
let params = new HttpParams()
|
||||||
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
|
|
||||||
|
return this.authHttp.get<ResultList<VideoAbuse>>(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) {
|
reportVideo (id: number, reason: string) {
|
||||||
|
const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse'
|
||||||
const body = {
|
const body = {
|
||||||
reason
|
reason
|
||||||
}
|
}
|
||||||
const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse'
|
|
||||||
|
|
||||||
return this.authHttp.post(url, body)
|
return this.authHttp.post(url, body)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractVideoAbuses (result: ResultList) {
|
private formatVideoAbuse (videoAbuse: VideoAbuse) {
|
||||||
const videoAbuses: VideoAbuse[] = result.data
|
return Object.assign(videoAbuse, {
|
||||||
const totalVideoAbuses = result.total
|
createdAt: Utils.dateToHuman(videoAbuse.createdAt)
|
||||||
|
})
|
||||||
return { videoAbuses, totalVideoAbuses }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './sort-field.type'
|
export * from './sort-field.type'
|
||||||
export * from './video.model'
|
export * from './video.model'
|
||||||
export * from './video.service'
|
export * from './video.service'
|
||||||
|
export * from './video-pagination.model'
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface VideoPagination {
|
||||||
|
currentPage: number
|
||||||
|
itemsPerPage: number
|
||||||
|
totalItems: number
|
||||||
|
}
|
|
@ -46,7 +46,7 @@ export class Video implements VideoServerModel {
|
||||||
|
|
||||||
constructor (hash: {
|
constructor (hash: {
|
||||||
author: string,
|
author: string,
|
||||||
createdAt: string,
|
createdAt: Date | string,
|
||||||
categoryLabel: string,
|
categoryLabel: string,
|
||||||
category: number,
|
category: number,
|
||||||
licenceLabel: string,
|
licenceLabel: string,
|
||||||
|
@ -70,7 +70,7 @@ export class Video implements VideoServerModel {
|
||||||
files: VideoFile[]
|
files: VideoFile[]
|
||||||
}) {
|
}) {
|
||||||
this.author = hash.author
|
this.author = hash.author
|
||||||
this.createdAt = new Date(hash.createdAt)
|
this.createdAt = new Date(hash.createdAt.toString())
|
||||||
this.categoryLabel = hash.categoryLabel
|
this.categoryLabel = hash.categoryLabel
|
||||||
this.category = hash.category
|
this.category = hash.category
|
||||||
this.licenceLabel = hash.licenceLabel
|
this.licenceLabel = hash.licenceLabel
|
||||||
|
|
|
@ -1,27 +1,26 @@
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Http, Headers, RequestOptions } from '@angular/http'
|
|
||||||
import { Observable } from 'rxjs/Observable'
|
import { Observable } from 'rxjs/Observable'
|
||||||
import 'rxjs/add/operator/catch'
|
import 'rxjs/add/operator/catch'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
|
|
||||||
import { Search } from '../../shared'
|
import { Search } from '../../shared'
|
||||||
import { SortField } from './sort-field.type'
|
import { SortField } from './sort-field.type'
|
||||||
import { AuthService } from '../../core'
|
|
||||||
import {
|
import {
|
||||||
AuthHttp,
|
|
||||||
RestExtractor,
|
RestExtractor,
|
||||||
RestPagination,
|
|
||||||
RestService,
|
RestService,
|
||||||
ResultList,
|
|
||||||
UserService
|
UserService
|
||||||
} from '../../shared'
|
} from '../../shared'
|
||||||
import { Video } from './video.model'
|
import { Video } from './video.model'
|
||||||
|
import { VideoPagination } from './video-pagination.model'
|
||||||
import {
|
import {
|
||||||
UserVideoRate,
|
UserVideoRate,
|
||||||
VideoRateType,
|
VideoRateType,
|
||||||
VideoUpdate,
|
VideoUpdate,
|
||||||
VideoAbuseCreate,
|
VideoAbuseCreate,
|
||||||
UserVideoRateUpdate
|
UserVideoRateUpdate,
|
||||||
|
Video as VideoServerModel,
|
||||||
|
ResultList
|
||||||
} from '../../../../../shared'
|
} from '../../../../../shared'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -33,9 +32,7 @@ export class VideoService {
|
||||||
videoLanguages: Array<{ id: number, label: string }> = []
|
videoLanguages: Array<{ id: number, label: string }> = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authService: AuthService,
|
private authHttp: HttpClient,
|
||||||
private authHttp: AuthHttp,
|
|
||||||
private http: Http,
|
|
||||||
private restExtractor: RestExtractor,
|
private restExtractor: RestExtractor,
|
||||||
private restService: RestService
|
private restService: RestService
|
||||||
) {}
|
) {}
|
||||||
|
@ -52,11 +49,10 @@ export class VideoService {
|
||||||
return this.loadVideoAttributeEnum('languages', this.videoLanguages)
|
return this.loadVideoAttributeEnum('languages', this.videoLanguages)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideo (uuid: string): Observable<Video> {
|
getVideo (uuid: string) {
|
||||||
return this.http.get(VideoService.BASE_VIDEO_URL + uuid)
|
return this.authHttp.get<VideoServerModel>(VideoService.BASE_VIDEO_URL + uuid)
|
||||||
.map(this.restExtractor.extractDataGet)
|
.map(videoHash => new Video(videoHash))
|
||||||
.map(videoHash => new Video(videoHash))
|
.catch((res) => this.restExtractor.handleError(res))
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVideo (video: Video) {
|
updateVideo (video: Video) {
|
||||||
|
@ -72,38 +68,41 @@ export class VideoService {
|
||||||
nsfw: video.nsfw
|
nsfw: video.nsfw
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers = new Headers({ 'Content-Type': 'application/json' })
|
return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body)
|
||||||
const options = new RequestOptions({ headers: headers })
|
|
||||||
|
|
||||||
return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body, options)
|
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch(this.restExtractor.handleError)
|
.catch(this.restExtractor.handleError)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideos (pagination: RestPagination, sort: SortField) {
|
getVideos (videoPagination: VideoPagination, sort: SortField) {
|
||||||
const params = this.restService.buildRestGetParams(pagination, sort)
|
const pagination = this.videoPaginationToRestPagination(videoPagination)
|
||||||
|
|
||||||
return this.http.get(VideoService.BASE_VIDEO_URL, { search: params })
|
let params = new HttpParams()
|
||||||
.map(res => res.json())
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
.map(this.extractVideos)
|
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
return this.authHttp.get(VideoService.BASE_VIDEO_URL, { params })
|
||||||
|
.map(this.extractVideos)
|
||||||
|
.catch((res) => this.restExtractor.handleError(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
searchVideos (search: Search, videoPagination: VideoPagination, sort: SortField) {
|
||||||
|
const url = VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value)
|
||||||
|
|
||||||
|
const pagination = this.videoPaginationToRestPagination(videoPagination)
|
||||||
|
|
||||||
|
let params = new HttpParams()
|
||||||
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
|
|
||||||
|
if (search.field) params.set('field', search.field)
|
||||||
|
|
||||||
|
return this.authHttp.get<ResultList<VideoServerModel>>(url, { params })
|
||||||
|
.map(this.extractVideos)
|
||||||
|
.catch((res) => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
removeVideo (id: number) {
|
removeVideo (id: number) {
|
||||||
return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id)
|
return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch((res) => this.restExtractor.handleError(res))
|
||||||
}
|
|
||||||
|
|
||||||
searchVideos (search: Search, pagination: RestPagination, sort: SortField) {
|
|
||||||
const params = this.restService.buildRestGetParams(pagination, sort)
|
|
||||||
|
|
||||||
if (search.field) params.set('field', search.field)
|
|
||||||
|
|
||||||
return this.http.get(VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value), { search: params })
|
|
||||||
.map(this.restExtractor.extractDataList)
|
|
||||||
.map(this.extractVideos)
|
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reportVideo (id: number, reason: string) {
|
reportVideo (id: number, reason: string) {
|
||||||
|
@ -114,7 +113,7 @@ export class VideoService {
|
||||||
|
|
||||||
return this.authHttp.post(url, body)
|
return this.authHttp.post(url, body)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
setVideoLike (id: number) {
|
setVideoLike (id: number) {
|
||||||
|
@ -129,14 +128,20 @@ export class VideoService {
|
||||||
const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating'
|
const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating'
|
||||||
|
|
||||||
return this.authHttp.get(url)
|
return this.authHttp.get(url)
|
||||||
.map(this.restExtractor.extractDataGet)
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blacklistVideo (id: number) {
|
blacklistVideo (id: number) {
|
||||||
return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {})
|
return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {})
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
private videoPaginationToRestPagination (videoPagination: VideoPagination) {
|
||||||
|
const start: number = (videoPagination.currentPage - 1) * videoPagination.itemsPerPage
|
||||||
|
const count: number = videoPagination.itemsPerPage
|
||||||
|
|
||||||
|
return { start, count }
|
||||||
}
|
}
|
||||||
|
|
||||||
private setVideoRate (id: number, rateType: VideoRateType) {
|
private setVideoRate (id: number, rateType: VideoRateType) {
|
||||||
|
@ -147,13 +152,14 @@ export class VideoService {
|
||||||
|
|
||||||
return this.authHttp.put(url, body)
|
return this.authHttp.put(url, body)
|
||||||
.map(this.restExtractor.extractDataBool)
|
.map(this.restExtractor.extractDataBool)
|
||||||
.catch((res) => this.restExtractor.handleError(res))
|
.catch(res => this.restExtractor.handleError(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractVideos (result: ResultList) {
|
private extractVideos (result: ResultList<VideoServerModel>) {
|
||||||
const videosJson = result.data
|
const videosJson = result.data
|
||||||
const totalVideos = result.total
|
const totalVideos = result.total
|
||||||
const videos = []
|
const videos = []
|
||||||
|
|
||||||
for (const videoJson of videosJson) {
|
for (const videoJson of videosJson) {
|
||||||
videos.push(new Video(videoJson))
|
videos.push(new Video(videoJson))
|
||||||
}
|
}
|
||||||
|
@ -162,15 +168,14 @@ export class VideoService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadVideoAttributeEnum (attributeName: 'categories' | 'licences' | 'languages', hashToPopulate: { id: number, label: string }[]) {
|
private loadVideoAttributeEnum (attributeName: 'categories' | 'licences' | 'languages', hashToPopulate: { id: number, label: string }[]) {
|
||||||
return this.http.get(VideoService.BASE_VIDEO_URL + attributeName)
|
return this.authHttp.get(VideoService.BASE_VIDEO_URL + attributeName)
|
||||||
.map(this.restExtractor.extractDataGet)
|
.subscribe(data => {
|
||||||
.subscribe(data => {
|
Object.keys(data).forEach(dataKey => {
|
||||||
Object.keys(data).forEach(dataKey => {
|
hashToPopulate.push({
|
||||||
hashToPopulate.push({
|
id: parseInt(dataKey, 10),
|
||||||
id: parseInt(dataKey, 10),
|
label: data[dataKey]
|
||||||
label: data[dataKey]
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,12 @@ import { NotificationsService } from 'angular2-notifications'
|
||||||
import {
|
import {
|
||||||
SortField,
|
SortField,
|
||||||
Video,
|
Video,
|
||||||
VideoService
|
VideoService,
|
||||||
|
VideoPagination
|
||||||
} from '../shared'
|
} from '../shared'
|
||||||
import { AuthService, AuthUser } from '../../core'
|
import { AuthService, AuthUser } from '../../core'
|
||||||
import { RestPagination, Search, SearchField } from '../../shared'
|
import { Search, SearchField, SearchService } from '../../shared'
|
||||||
import { SearchService } from '../../shared'
|
import { } from '../../shared'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-videos-list',
|
selector: 'my-videos-list',
|
||||||
|
@ -21,7 +22,7 @@ import { SearchService } from '../../shared'
|
||||||
})
|
})
|
||||||
export class VideoListComponent implements OnInit, OnDestroy {
|
export class VideoListComponent implements OnInit, OnDestroy {
|
||||||
loading: BehaviorSubject<boolean> = new BehaviorSubject(false)
|
loading: BehaviorSubject<boolean> = new BehaviorSubject(false)
|
||||||
pagination: RestPagination = {
|
pagination: VideoPagination = {
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
itemsPerPage: 25,
|
itemsPerPage: 25,
|
||||||
totalItems: null
|
totalItems: null
|
||||||
|
@ -152,6 +153,6 @@ export class VideoListComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
private navigateToNewParams () {
|
private navigateToNewParams () {
|
||||||
const routeParams = this.buildRouteParams()
|
const routeParams = this.buildRouteParams()
|
||||||
this.router.navigate(['/videos/list', routeParams])
|
this.router.navigate([ '/videos/list', routeParams ])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
@import '../../node_modules/video.js/dist/video-js.css';
|
@import '~primeng/resources/themes/bootstrap/theme.css';
|
||||||
|
@import '~primeng/resources/primeng.css';
|
||||||
|
@import '~video.js/dist/video-js.css';
|
||||||
@import './video-js-custom.scss';
|
@import './video-js-custom.scss';
|
||||||
|
|
||||||
[hidden] {
|
[hidden] {
|
||||||
|
@ -45,23 +47,13 @@ input.readonly {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some fixes for ng2-smart-table */
|
/* ngprime data table customizations */
|
||||||
ng2-smart-table {
|
p-datatable {
|
||||||
thead tr {
|
.action-cell {
|
||||||
border-top: 1px solid rgb(233, 235, 236)
|
text-align: center;
|
||||||
}
|
|
||||||
|
|
||||||
td, th {
|
.glyphicon {
|
||||||
padding: 8px !important;
|
cursor: pointer;
|
||||||
color: #333333 !important;
|
}
|
||||||
font-size: 14px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ng2-smart-pagination-nav .page-link {
|
|
||||||
font-size: 11px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.glyphicon {
|
|
||||||
font-family: 'Glyphicons Halflings' !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4436,10 +4436,6 @@ ng-router-loader@^2.0.0:
|
||||||
loader-utils "^0.2.16"
|
loader-utils "^0.2.16"
|
||||||
recast "^0.11.20"
|
recast "^0.11.20"
|
||||||
|
|
||||||
ng2-completer@^1.2.2:
|
|
||||||
version "1.6.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ng2-completer/-/ng2-completer-1.6.1.tgz#62bad1a0a1d99c62b15f6723911ee0a3a00c91bb"
|
|
||||||
|
|
||||||
ng2-file-upload@^1.1.4-2:
|
ng2-file-upload@^1.1.4-2:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/ng2-file-upload/-/ng2-file-upload-1.2.1.tgz#5563c5dfd6f43fbfbe815c206e343464a0a6a197"
|
resolved "https://registry.yarnpkg.com/ng2-file-upload/-/ng2-file-upload-1.2.1.tgz#5563c5dfd6f43fbfbe815c206e343464a0a6a197"
|
||||||
|
@ -4448,13 +4444,6 @@ ng2-material-dropdown@0.7.10:
|
||||||
version "0.7.10"
|
version "0.7.10"
|
||||||
resolved "https://registry.yarnpkg.com/ng2-material-dropdown/-/ng2-material-dropdown-0.7.10.tgz#093471f2a9cadd726cbcb120b0ad7818a54fa5ed"
|
resolved "https://registry.yarnpkg.com/ng2-material-dropdown/-/ng2-material-dropdown-0.7.10.tgz#093471f2a9cadd726cbcb120b0ad7818a54fa5ed"
|
||||||
|
|
||||||
ng2-smart-table@1.2.1:
|
|
||||||
version "1.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ng2-smart-table/-/ng2-smart-table-1.2.1.tgz#b25102c1a8b0588c508cf913c539ddf0f0b3341d"
|
|
||||||
dependencies:
|
|
||||||
lodash "^4.17.4"
|
|
||||||
ng2-completer "^1.2.2"
|
|
||||||
|
|
||||||
ngc-webpack@3.2.2:
|
ngc-webpack@3.2.2:
|
||||||
version "3.2.2"
|
version "3.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/ngc-webpack/-/ngc-webpack-3.2.2.tgz#1905c40e3c7d30c86fe029c7a7fda71cb4dc59df"
|
resolved "https://registry.yarnpkg.com/ngc-webpack/-/ngc-webpack-3.2.2.tgz#1905c40e3c7d30c86fe029c7a7fda71cb4dc59df"
|
||||||
|
@ -5340,6 +5329,10 @@ pretty-error@^2.0.2:
|
||||||
renderkid "^2.0.1"
|
renderkid "^2.0.1"
|
||||||
utila "~0.4"
|
utila "~0.4"
|
||||||
|
|
||||||
|
primeng@^4.2.0:
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/primeng/-/primeng-4.2.0.tgz#49c8c99de26d254f41d3fbb8759227fe1d269772"
|
||||||
|
|
||||||
private@^0.1.6, private@^0.1.7, private@~0.1.5:
|
private@^0.1.6, private@^0.1.7, private@~0.1.5:
|
||||||
version "0.1.7"
|
version "0.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
|
resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
|
||||||
|
|
|
@ -190,6 +190,7 @@ function quitFriends () {
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.error('Some errors while quitting friends.', err)
|
logger.error('Some errors while quitting friends.', err)
|
||||||
// Don't stop the process
|
// Don't stop the process
|
||||||
|
return pods
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.then(pods => {
|
.then(pods => {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
export * from './user.model'
|
export * from './user.model'
|
||||||
export * from './user-create.model'
|
export * from './user-create.model'
|
||||||
|
export * from './user-login.model'
|
||||||
|
export * from './user-refresh-token.model'
|
||||||
export * from './user-update.model'
|
export * from './user-update.model'
|
||||||
export * from './user-update-me.model'
|
export * from './user-update-me.model'
|
||||||
export * from './user-role.type'
|
export * from './user-role.type'
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface UserLogin {
|
||||||
|
access_token: string
|
||||||
|
refresh_token: string
|
||||||
|
token_type: string
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface UserRefreshToken {
|
||||||
|
access_token: string
|
||||||
|
refresh_token: string
|
||||||
|
}
|
|
@ -9,8 +9,8 @@ export interface Video {
|
||||||
id: number
|
id: number
|
||||||
uuid: string
|
uuid: string
|
||||||
author: string
|
author: string
|
||||||
createdAt: Date
|
createdAt: Date | string
|
||||||
updatedAt: Date
|
updatedAt: Date | string
|
||||||
categoryLabel: string
|
categoryLabel: string
|
||||||
category: number
|
category: number
|
||||||
licenceLabel: string
|
licenceLabel: string
|
||||||
|
|
Loading…
Reference in New Issue