diff options
Diffstat (limited to 'client/src/app/+admin')
47 files changed, 983 insertions, 0 deletions
diff --git a/client/src/app/+admin/admin-routing.module.ts b/client/src/app/+admin/admin-routing.module.ts new file mode 100644 index 000000000..d3adf3f3b --- /dev/null +++ b/client/src/app/+admin/admin-routing.module.ts | |||
@@ -0,0 +1,32 @@ | |||
1 | import { NgModule } from '@angular/core'; | ||
2 | import { RouterModule, Routes } from '@angular/router'; | ||
3 | |||
4 | import { AdminComponent } from './admin.component'; | ||
5 | import { FriendsRoutes } from './friends'; | ||
6 | import { RequestsRoutes } from './requests'; | ||
7 | import { UsersRoutes } from './users'; | ||
8 | import { VideoAbusesRoutes } from './video-abuses'; | ||
9 | |||
10 | const adminRoutes: Routes = [ | ||
11 | { | ||
12 | path: '', | ||
13 | component: AdminComponent, | ||
14 | children: [ | ||
15 | { | ||
16 | path: '', | ||
17 | redirectTo: 'users', | ||
18 | pathMatch: 'full' | ||
19 | }, | ||
20 | ...FriendsRoutes, | ||
21 | ...RequestsRoutes, | ||
22 | ...UsersRoutes, | ||
23 | ...VideoAbusesRoutes | ||
24 | ] | ||
25 | } | ||
26 | ]; | ||
27 | |||
28 | @NgModule({ | ||
29 | imports: [ RouterModule.forChild(adminRoutes) ], | ||
30 | exports: [ RouterModule ] | ||
31 | }) | ||
32 | export class AdminRoutingModule {} | ||
diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts new file mode 100644 index 000000000..64a7400e7 --- /dev/null +++ b/client/src/app/+admin/admin.component.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { Component } from '@angular/core'; | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | |||
7 | export class AdminComponent { | ||
8 | } | ||
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts new file mode 100644 index 000000000..db1ce2d7f --- /dev/null +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -0,0 +1,45 @@ | |||
1 | import { NgModule } from '@angular/core'; | ||
2 | |||
3 | import { AdminComponent } from './admin.component'; | ||
4 | import { AdminRoutingModule } from './admin-routing.module'; | ||
5 | import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends'; | ||
6 | import { RequestsComponent, RequestStatsComponent, RequestService } from './requests'; | ||
7 | import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users'; | ||
8 | import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses'; | ||
9 | import { SharedModule } from '../shared'; | ||
10 | |||
11 | @NgModule({ | ||
12 | imports: [ | ||
13 | AdminRoutingModule, | ||
14 | SharedModule | ||
15 | ], | ||
16 | |||
17 | declarations: [ | ||
18 | AdminComponent, | ||
19 | |||
20 | FriendsComponent, | ||
21 | FriendAddComponent, | ||
22 | FriendListComponent, | ||
23 | |||
24 | RequestsComponent, | ||
25 | RequestStatsComponent, | ||
26 | |||
27 | UsersComponent, | ||
28 | UserAddComponent, | ||
29 | UserListComponent, | ||
30 | |||
31 | VideoAbusesComponent, | ||
32 | VideoAbuseListComponent | ||
33 | ], | ||
34 | |||
35 | exports: [ | ||
36 | AdminComponent | ||
37 | ], | ||
38 | |||
39 | providers: [ | ||
40 | FriendService, | ||
41 | RequestService, | ||
42 | UserService | ||
43 | ] | ||
44 | }) | ||
45 | export class AdminModule { } | ||
diff --git a/client/src/app/+admin/friends/friend-add/friend-add.component.html b/client/src/app/+admin/friends/friend-add/friend-add.component.html new file mode 100644 index 000000000..eebe033f9 --- /dev/null +++ b/client/src/app/+admin/friends/friend-add/friend-add.component.html | |||
@@ -0,0 +1,30 @@ | |||
1 | <h3>Make friends</h3> | ||
2 | |||
3 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | ||
4 | |||
5 | <form (ngSubmit)="makeFriends()" [formGroup]="form"> | ||
6 | <div class="form-group" *ngFor="let host of hosts; let id = index; trackBy:customTrackBy"> | ||
7 | <label for="username">Host</label> | ||
8 | |||
9 | <div class="input-group"> | ||
10 | <input | ||
11 | type="text" class="form-control" placeholder="domain.tld" | ||
12 | [id]="'host-' + id" [formControlName]="'host-' + id" | ||
13 | /> | ||
14 | <span class="input-group-btn"> | ||
15 | <button *ngIf="displayAddField(id)" (click)="addField()" class="btn btn-default" type="button">+</button> | ||
16 | <button *ngIf="displayRemoveField(id)" (click)="removeField(id)" class="btn btn-default" type="button">-</button> | ||
17 | </span> | ||
18 | </div> | ||
19 | |||
20 | <div [hidden]="form.controls['host-' + id].valid || form.controls['host-' + id].pristine" class="alert alert-warning"> | ||
21 | It should be a valid host. | ||
22 | </div> | ||
23 | </div> | ||
24 | |||
25 | <div *ngIf="canMakeFriends() === false" class="alert alert-warning"> | ||
26 | It seems that you are not on a HTTPS pod. Your webserver need to have TLS activated in order to make friends. | ||
27 | </div> | ||
28 | |||
29 | <input type="submit" value="Make friends" class="btn btn-default" [disabled]="!isFormValid()"> | ||
30 | </form> | ||
diff --git a/client/src/app/+admin/friends/friend-add/friend-add.component.scss b/client/src/app/+admin/friends/friend-add/friend-add.component.scss new file mode 100644 index 000000000..5fde51636 --- /dev/null +++ b/client/src/app/+admin/friends/friend-add/friend-add.component.scss | |||
@@ -0,0 +1,7 @@ | |||
1 | table { | ||
2 | margin-bottom: 40px; | ||
3 | } | ||
4 | |||
5 | .input-group-btn button { | ||
6 | width: 35px; | ||
7 | } | ||
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 new file mode 100644 index 000000000..014252011 --- /dev/null +++ b/client/src/app/+admin/friends/friend-add/friend-add.component.ts | |||
@@ -0,0 +1,107 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | ||
2 | import { FormControl, FormGroup } from '@angular/forms'; | ||
3 | import { Router } from '@angular/router'; | ||
4 | |||
5 | import { validateHost } from '../../../shared'; | ||
6 | import { FriendService } from '../shared'; | ||
7 | |||
8 | @Component({ | ||
9 | selector: 'my-friend-add', | ||
10 | templateUrl: './friend-add.component.html', | ||
11 | styleUrls: [ './friend-add.component.scss' ] | ||
12 | }) | ||
13 | export class FriendAddComponent implements OnInit { | ||
14 | form: FormGroup; | ||
15 | hosts = [ ]; | ||
16 | error: string = null; | ||
17 | |||
18 | constructor(private router: Router, private friendService: FriendService) {} | ||
19 | |||
20 | ngOnInit() { | ||
21 | this.form = new FormGroup({}); | ||
22 | this.addField(); | ||
23 | } | ||
24 | |||
25 | addField() { | ||
26 | this.form.addControl(`host-${this.hosts.length}`, new FormControl('', [ validateHost ])); | ||
27 | this.hosts.push(''); | ||
28 | } | ||
29 | |||
30 | canMakeFriends() { | ||
31 | return window.location.protocol === 'https:'; | ||
32 | } | ||
33 | |||
34 | customTrackBy(index: number, obj: any): any { | ||
35 | return index; | ||
36 | } | ||
37 | |||
38 | displayAddField(index: number) { | ||
39 | return index === (this.hosts.length - 1); | ||
40 | } | ||
41 | |||
42 | displayRemoveField(index: number) { | ||
43 | return (index !== 0 || this.hosts.length > 1) && index !== (this.hosts.length - 1); | ||
44 | } | ||
45 | |||
46 | isFormValid() { | ||
47 | // Do not check the last input | ||
48 | for (let i = 0; i < this.hosts.length - 1; i++) { | ||
49 | if (!this.form.controls[`host-${i}`].valid) return false; | ||
50 | } | ||
51 | |||
52 | const lastIndex = this.hosts.length - 1; | ||
53 | // If the last input (which is not the first) is empty, it's ok | ||
54 | if (this.hosts[lastIndex] === '' && lastIndex !== 0) { | ||
55 | return true; | ||
56 | } else { | ||
57 | return this.form.controls[`host-${lastIndex}`].valid; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | removeField(index: number) { | ||
62 | // Remove the last control | ||
63 | this.form.removeControl(`host-${this.hosts.length - 1}`); | ||
64 | this.hosts.splice(index, 1); | ||
65 | } | ||
66 | |||
67 | makeFriends() { | ||
68 | this.error = ''; | ||
69 | |||
70 | const notEmptyHosts = this.getNotEmptyHosts(); | ||
71 | if (notEmptyHosts.length === 0) { | ||
72 | this.error = 'You need to specify at least 1 host.'; | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | if (!this.isHostsUnique(notEmptyHosts)) { | ||
77 | this.error = 'Hosts need to be unique.'; | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | const confirmMessage = 'Are you sure to make friends with:\n - ' + notEmptyHosts.join('\n - '); | ||
82 | if (!confirm(confirmMessage)) return; | ||
83 | |||
84 | this.friendService.makeFriends(notEmptyHosts).subscribe( | ||
85 | status => { | ||
86 | alert('Make friends request sent!'); | ||
87 | this.router.navigate([ '/admin/friends/list' ]); | ||
88 | }, | ||
89 | error => alert(error.text) | ||
90 | ); | ||
91 | } | ||
92 | |||
93 | private getNotEmptyHosts() { | ||
94 | const notEmptyHosts = []; | ||
95 | |||
96 | Object.keys(this.form.value).forEach((hostKey) => { | ||
97 | const host = this.form.value[hostKey]; | ||
98 | if (host !== '') notEmptyHosts.push(host); | ||
99 | }); | ||
100 | |||
101 | return notEmptyHosts; | ||
102 | } | ||
103 | |||
104 | private isHostsUnique(hosts: string[]) { | ||
105 | return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host)); | ||
106 | } | ||
107 | } | ||
diff --git a/client/src/app/+admin/friends/friend-add/index.ts b/client/src/app/+admin/friends/friend-add/index.ts new file mode 100644 index 000000000..a101b3be5 --- /dev/null +++ b/client/src/app/+admin/friends/friend-add/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './friend-add.component'; | |||
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 new file mode 100644 index 000000000..06258f8c8 --- /dev/null +++ b/client/src/app/+admin/friends/friend-list/friend-list.component.html | |||
@@ -0,0 +1,29 @@ | |||
1 | <h3>Friends list</h3> | ||
2 | |||
3 | <table class="table table-hover"> | ||
4 | <thead> | ||
5 | <tr> | ||
6 | <th class="table-column-id">ID</th> | ||
7 | <th>Host</th> | ||
8 | <th>Score</th> | ||
9 | <th>Created Date</th> | ||
10 | </tr> | ||
11 | </thead> | ||
12 | |||
13 | <tbody> | ||
14 | <tr *ngFor="let friend of friends"> | ||
15 | <td>{{ friend.id }}</td> | ||
16 | <td>{{ friend.host }}</td> | ||
17 | <td>{{ friend.score }}</td> | ||
18 | <td>{{ friend.createdAt | date: 'medium' }}</td> | ||
19 | </tr> | ||
20 | </tbody> | ||
21 | </table> | ||
22 | |||
23 | <a *ngIf="friends && friends.length !== 0" class="add-user btn btn-danger pull-left" (click)="quitFriends()"> | ||
24 | Quit friends | ||
25 | </a> | ||
26 | |||
27 | <a *ngIf="friends?.length === 0" class="add-user btn btn-success pull-right" [routerLink]="['/admin/friends/add']"> | ||
28 | Make friends | ||
29 | </a> | ||
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.scss b/client/src/app/+admin/friends/friend-list/friend-list.component.scss new file mode 100644 index 000000000..cb597e12b --- /dev/null +++ b/client/src/app/+admin/friends/friend-list/friend-list.component.scss | |||
@@ -0,0 +1,3 @@ | |||
1 | table { | ||
2 | margin-bottom: 40px; | ||
3 | } | ||
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 new file mode 100644 index 000000000..bec10162c --- /dev/null +++ b/client/src/app/+admin/friends/friend-list/friend-list.component.ts | |||
@@ -0,0 +1,38 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | ||
2 | |||
3 | import { Friend, FriendService } from '../shared'; | ||
4 | |||
5 | @Component({ | ||
6 | selector: 'my-friend-list', | ||
7 | templateUrl: './friend-list.component.html', | ||
8 | styleUrls: [ './friend-list.component.scss' ] | ||
9 | }) | ||
10 | export class FriendListComponent implements OnInit { | ||
11 | friends: Friend[]; | ||
12 | |||
13 | constructor(private friendService: FriendService) { } | ||
14 | |||
15 | ngOnInit() { | ||
16 | this.getFriends(); | ||
17 | } | ||
18 | |||
19 | quitFriends() { | ||
20 | if (!confirm('Are you sure?')) return; | ||
21 | |||
22 | this.friendService.quitFriends().subscribe( | ||
23 | status => { | ||
24 | alert('Quit friends!'); | ||
25 | this.getFriends(); | ||
26 | }, | ||
27 | error => alert(error.text) | ||
28 | ); | ||
29 | } | ||
30 | |||
31 | private getFriends() { | ||
32 | this.friendService.getFriends().subscribe( | ||
33 | res => this.friends = res.friends, | ||
34 | |||
35 | err => alert(err.text) | ||
36 | ); | ||
37 | } | ||
38 | } | ||
diff --git a/client/src/app/+admin/friends/friend-list/index.ts b/client/src/app/+admin/friends/friend-list/index.ts new file mode 100644 index 000000000..354c978a4 --- /dev/null +++ b/client/src/app/+admin/friends/friend-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './friend-list.component'; | |||
diff --git a/client/src/app/+admin/friends/friends.component.ts b/client/src/app/+admin/friends/friends.component.ts new file mode 100644 index 000000000..bc3f54158 --- /dev/null +++ b/client/src/app/+admin/friends/friends.component.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { Component } from '@angular/core'; | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | |||
7 | export class FriendsComponent { | ||
8 | } | ||
diff --git a/client/src/app/+admin/friends/friends.routes.ts b/client/src/app/+admin/friends/friends.routes.ts new file mode 100644 index 000000000..a9a06539b --- /dev/null +++ b/client/src/app/+admin/friends/friends.routes.ts | |||
@@ -0,0 +1,37 @@ | |||
1 | import { Routes } from '@angular/router'; | ||
2 | |||
3 | import { FriendsComponent } from './friends.component'; | ||
4 | import { FriendAddComponent } from './friend-add'; | ||
5 | import { FriendListComponent } from './friend-list'; | ||
6 | |||
7 | export const FriendsRoutes: Routes = [ | ||
8 | { | ||
9 | path: 'friends', | ||
10 | component: FriendsComponent, | ||
11 | children: [ | ||
12 | { | ||
13 | path: '', | ||
14 | redirectTo: 'list', | ||
15 | pathMatch: 'full' | ||
16 | }, | ||
17 | { | ||
18 | path: 'list', | ||
19 | component: FriendListComponent, | ||
20 | data: { | ||
21 | meta: { | ||
22 | titleSuffix: ' - Friends list' | ||
23 | } | ||
24 | } | ||
25 | }, | ||
26 | { | ||
27 | path: 'add', | ||
28 | component: FriendAddComponent, | ||
29 | data: { | ||
30 | meta: { | ||
31 | titleSuffix: ' - Add friends' | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | ] | ||
36 | } | ||
37 | ]; | ||
diff --git a/client/src/app/+admin/friends/index.ts b/client/src/app/+admin/friends/index.ts new file mode 100644 index 000000000..dd4df2538 --- /dev/null +++ b/client/src/app/+admin/friends/index.ts | |||
@@ -0,0 +1,5 @@ | |||
1 | export * from './friend-add'; | ||
2 | export * from './friend-list'; | ||
3 | export * from './shared'; | ||
4 | export * from './friends.component'; | ||
5 | export * from './friends.routes'; | ||
diff --git a/client/src/app/+admin/friends/shared/friend.model.ts b/client/src/app/+admin/friends/shared/friend.model.ts new file mode 100644 index 000000000..462cc82ed --- /dev/null +++ b/client/src/app/+admin/friends/shared/friend.model.ts | |||
@@ -0,0 +1,6 @@ | |||
1 | export interface Friend { | ||
2 | id: string; | ||
3 | host: string; | ||
4 | score: number; | ||
5 | createdAt: Date; | ||
6 | } | ||
diff --git a/client/src/app/+admin/friends/shared/friend.service.ts b/client/src/app/+admin/friends/shared/friend.service.ts new file mode 100644 index 000000000..e97459385 --- /dev/null +++ b/client/src/app/+admin/friends/shared/friend.service.ts | |||
@@ -0,0 +1,47 @@ | |||
1 | import { Injectable } from '@angular/core'; | ||
2 | import { Observable } from 'rxjs/Observable'; | ||
3 | import 'rxjs/add/operator/catch'; | ||
4 | import 'rxjs/add/operator/map'; | ||
5 | |||
6 | import { Friend } from './friend.model'; | ||
7 | import { AuthHttp, RestExtractor, ResultList } from '../../../shared'; | ||
8 | |||
9 | @Injectable() | ||
10 | export class FriendService { | ||
11 | private static BASE_FRIEND_URL: string = '/api/v1/pods/'; | ||
12 | |||
13 | constructor ( | ||
14 | private authHttp: AuthHttp, | ||
15 | private restExtractor: RestExtractor | ||
16 | ) {} | ||
17 | |||
18 | getFriends() { | ||
19 | return this.authHttp.get(FriendService.BASE_FRIEND_URL) | ||
20 | .map(this.restExtractor.extractDataList) | ||
21 | .map(this.extractFriends) | ||
22 | .catch((res) => this.restExtractor.handleError(res)); | ||
23 | } | ||
24 | |||
25 | makeFriends(notEmptyHosts) { | ||
26 | const body = { | ||
27 | hosts: notEmptyHosts | ||
28 | }; | ||
29 | |||
30 | return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'makefriends', body) | ||
31 | .map(this.restExtractor.extractDataBool) | ||
32 | .catch((res) => this.restExtractor.handleError(res)); | ||
33 | } | ||
34 | |||
35 | quitFriends() { | ||
36 | return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quitfriends') | ||
37 | .map(res => res.status) | ||
38 | .catch((res) => this.restExtractor.handleError(res)); | ||
39 | } | ||
40 | |||
41 | private extractFriends(result: ResultList) { | ||
42 | const friends: Friend[] = result.data; | ||
43 | const totalFriends = result.total; | ||
44 | |||
45 | return { friends, totalFriends }; | ||
46 | } | ||
47 | } | ||
diff --git a/client/src/app/+admin/friends/shared/index.ts b/client/src/app/+admin/friends/shared/index.ts new file mode 100644 index 000000000..0d671637d --- /dev/null +++ b/client/src/app/+admin/friends/shared/index.ts | |||
@@ -0,0 +1,2 @@ | |||
1 | export * from './friend.model'; | ||
2 | export * from './friend.service'; | ||
diff --git a/client/src/app/+admin/index.ts b/client/src/app/+admin/index.ts new file mode 100644 index 000000000..2f47a3cc3 --- /dev/null +++ b/client/src/app/+admin/index.ts | |||
@@ -0,0 +1,6 @@ | |||
1 | export * from './friends'; | ||
2 | export * from './requests'; | ||
3 | export * from './users'; | ||
4 | export * from './admin-routing.module'; | ||
5 | export * from './admin.module'; | ||
6 | export * from './admin.component'; | ||
diff --git a/client/src/app/+admin/requests/index.ts b/client/src/app/+admin/requests/index.ts new file mode 100644 index 000000000..236a9ee8f --- /dev/null +++ b/client/src/app/+admin/requests/index.ts | |||
@@ -0,0 +1,4 @@ | |||
1 | export * from './request-stats'; | ||
2 | export * from './shared'; | ||
3 | export * from './requests.component'; | ||
4 | export * from './requests.routes'; | ||
diff --git a/client/src/app/+admin/requests/request-stats/index.ts b/client/src/app/+admin/requests/request-stats/index.ts new file mode 100644 index 000000000..be3a66f77 --- /dev/null +++ b/client/src/app/+admin/requests/request-stats/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './request-stats.component'; | |||
diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.html b/client/src/app/+admin/requests/request-stats/request-stats.component.html new file mode 100644 index 000000000..9dbed1739 --- /dev/null +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.html | |||
@@ -0,0 +1,33 @@ | |||
1 | <h3>Requests stats</h3> | ||
2 | |||
3 | <div *ngIf="stats !== null"> | ||
4 | <div class="requests-general"> | ||
5 | <div> | ||
6 | <span class="label-description">Remaining requests:</span> | ||
7 | {{ stats.totalRequests }} | ||
8 | </div> | ||
9 | |||
10 | <div> | ||
11 | <span class="label-description">Interval seconds between requests:</span> | ||
12 | {{ stats.secondsInterval }} | ||
13 | </div> | ||
14 | |||
15 | <div> | ||
16 | <span class="label-description">Remaining time before the scheduled request:</span> | ||
17 | {{ stats.remainingSeconds }} | ||
18 | </div> | ||
19 | </div> | ||
20 | |||
21 | <div class="requests-limit"> | ||
22 | <div> | ||
23 | <span class="label-description">Maximum number of different pods for a scheduled request:</span> | ||
24 | {{ stats.requestsLimitPods }} | ||
25 | </div> | ||
26 | |||
27 | <div> | ||
28 | <span class="label-description">Maximum number of requests per pod for a scheduled request:</span> | ||
29 | {{ stats.requestsLimitPerPod }} | ||
30 | </div> | ||
31 | </div> | ||
32 | |||
33 | </div> | ||
diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.scss b/client/src/app/+admin/requests/request-stats/request-stats.component.scss new file mode 100644 index 000000000..9c68fba99 --- /dev/null +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.scss | |||
@@ -0,0 +1,19 @@ | |||
1 | .label-description { | ||
2 | display: inline-block; | ||
3 | font-weight: bold; | ||
4 | color: black; | ||
5 | } | ||
6 | |||
7 | .requests-general { | ||
8 | .label-description { | ||
9 | width: 320px; | ||
10 | } | ||
11 | } | ||
12 | |||
13 | .requests-limit { | ||
14 | margin-top: 20px; | ||
15 | |||
16 | .label-description { | ||
17 | width: 430px; | ||
18 | } | ||
19 | } | ||
diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.ts b/client/src/app/+admin/requests/request-stats/request-stats.component.ts new file mode 100644 index 000000000..23b836779 --- /dev/null +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.ts | |||
@@ -0,0 +1,48 @@ | |||
1 | import { setInterval } from 'timers' | ||
2 | import { Component, OnInit, OnDestroy } from '@angular/core'; | ||
3 | |||
4 | import { RequestService, RequestStats } from '../shared'; | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-request-stats', | ||
8 | templateUrl: './request-stats.component.html', | ||
9 | styleUrls: [ './request-stats.component.scss' ] | ||
10 | }) | ||
11 | export class RequestStatsComponent implements OnInit, OnDestroy { | ||
12 | stats: RequestStats = null; | ||
13 | |||
14 | private interval: NodeJS.Timer = null; | ||
15 | |||
16 | constructor(private requestService: RequestService) { } | ||
17 | |||
18 | ngOnInit() { | ||
19 | this.getStats(); | ||
20 | this.runInterval(); | ||
21 | } | ||
22 | |||
23 | ngOnDestroy() { | ||
24 | if (this.stats !== null && this.stats.secondsInterval !== null) { | ||
25 | clearInterval(this.interval); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | getStats() { | ||
30 | this.requestService.getStats().subscribe( | ||
31 | stats => this.stats = stats, | ||
32 | |||
33 | err => alert(err.text) | ||
34 | ); | ||
35 | } | ||
36 | |||
37 | private runInterval() { | ||
38 | this.interval = setInterval(() => { | ||
39 | this.stats.remainingMilliSeconds -= 1000; | ||
40 | |||
41 | if (this.stats.remainingMilliSeconds <= 0) { | ||
42 | setTimeout(() => this.getStats(), this.stats.remainingMilliSeconds + 100); | ||
43 | } | ||
44 | }, 1000); | ||
45 | } | ||
46 | |||
47 | |||
48 | } | ||
diff --git a/client/src/app/+admin/requests/requests.component.ts b/client/src/app/+admin/requests/requests.component.ts new file mode 100644 index 000000000..471112b45 --- /dev/null +++ b/client/src/app/+admin/requests/requests.component.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { Component } from '@angular/core'; | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | |||
7 | export class RequestsComponent { | ||
8 | } | ||
diff --git a/client/src/app/+admin/requests/requests.routes.ts b/client/src/app/+admin/requests/requests.routes.ts new file mode 100644 index 000000000..70fbf41c3 --- /dev/null +++ b/client/src/app/+admin/requests/requests.routes.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import { Routes } from '@angular/router'; | ||
2 | |||
3 | import { RequestsComponent } from './requests.component'; | ||
4 | import { RequestStatsComponent } from './request-stats'; | ||
5 | |||
6 | export const RequestsRoutes: Routes = [ | ||
7 | { | ||
8 | path: 'requests', | ||
9 | component: RequestsComponent, | ||
10 | children: [ | ||
11 | { | ||
12 | path: '', | ||
13 | redirectTo: 'stats', | ||
14 | pathMatch: 'full' | ||
15 | }, | ||
16 | { | ||
17 | path: 'stats', | ||
18 | component: RequestStatsComponent, | ||
19 | data: { | ||
20 | meta: { | ||
21 | titleSuffix: ' - Request stats' | ||
22 | } | ||
23 | } | ||
24 | } | ||
25 | ] | ||
26 | } | ||
27 | ]; | ||
diff --git a/client/src/app/+admin/requests/shared/index.ts b/client/src/app/+admin/requests/shared/index.ts new file mode 100644 index 000000000..32ab5767b --- /dev/null +++ b/client/src/app/+admin/requests/shared/index.ts | |||
@@ -0,0 +1,2 @@ | |||
1 | export * from './request-stats.model'; | ||
2 | export * from './request.service'; | ||
diff --git a/client/src/app/+admin/requests/shared/request-stats.model.ts b/client/src/app/+admin/requests/shared/request-stats.model.ts new file mode 100644 index 000000000..f658c4682 --- /dev/null +++ b/client/src/app/+admin/requests/shared/request-stats.model.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | export interface Request { | ||
2 | request: any; | ||
3 | to: any; | ||
4 | } | ||
5 | |||
6 | export class RequestStats { | ||
7 | requestsLimitPods: number; | ||
8 | requestsLimitPerPod: number; | ||
9 | milliSecondsInterval: number; | ||
10 | remainingMilliSeconds: number; | ||
11 | totalRequests: number; | ||
12 | |||
13 | constructor(hash: { | ||
14 | requestsLimitPods: number, | ||
15 | requestsLimitPerPod: number, | ||
16 | milliSecondsInterval: number, | ||
17 | remainingMilliSeconds: number, | ||
18 | totalRequests: number; | ||
19 | }) { | ||
20 | this.requestsLimitPods = hash.requestsLimitPods; | ||
21 | this.requestsLimitPerPod = hash.requestsLimitPerPod; | ||
22 | this.milliSecondsInterval = hash.milliSecondsInterval; | ||
23 | this.remainingMilliSeconds = hash.remainingMilliSeconds; | ||
24 | this.totalRequests = hash.totalRequests; | ||
25 | } | ||
26 | |||
27 | get remainingSeconds() { | ||
28 | return Math.floor(this.remainingMilliSeconds / 1000); | ||
29 | } | ||
30 | |||
31 | get secondsInterval() { | ||
32 | return Math.floor(this.milliSecondsInterval / 1000); | ||
33 | } | ||
34 | |||
35 | } | ||
diff --git a/client/src/app/+admin/requests/shared/request.service.ts b/client/src/app/+admin/requests/shared/request.service.ts new file mode 100644 index 000000000..55b28bcfc --- /dev/null +++ b/client/src/app/+admin/requests/shared/request.service.ts | |||
@@ -0,0 +1,24 @@ | |||
1 | import { Injectable } from '@angular/core'; | ||
2 | import { Observable } from 'rxjs/Observable'; | ||
3 | import 'rxjs/add/operator/catch'; | ||
4 | import 'rxjs/add/operator/map'; | ||
5 | |||
6 | import { RequestStats } from './request-stats.model'; | ||
7 | import { AuthHttp, RestExtractor } from '../../../shared'; | ||
8 | |||
9 | @Injectable() | ||
10 | export class RequestService { | ||
11 | private static BASE_REQUEST_URL: string = '/api/v1/requests/'; | ||
12 | |||
13 | constructor ( | ||
14 | private authHttp: AuthHttp, | ||
15 | private restExtractor: RestExtractor | ||
16 | ) {} | ||
17 | |||
18 | getStats(): Observable<RequestStats> { | ||
19 | return this.authHttp.get(RequestService.BASE_REQUEST_URL + 'stats') | ||
20 | .map(this.restExtractor.extractDataGet) | ||
21 | .map((data) => new RequestStats(data)) | ||
22 | .catch((res) => this.restExtractor.handleError(res)); | ||
23 | } | ||
24 | } | ||
diff --git a/client/src/app/+admin/users/index.ts b/client/src/app/+admin/users/index.ts new file mode 100644 index 000000000..e98a81f62 --- /dev/null +++ b/client/src/app/+admin/users/index.ts | |||
@@ -0,0 +1,5 @@ | |||
1 | export * from './shared'; | ||
2 | export * from './user-add'; | ||
3 | export * from './user-list'; | ||
4 | export * from './users.component'; | ||
5 | export * from './users.routes'; | ||
diff --git a/client/src/app/+admin/users/shared/index.ts b/client/src/app/+admin/users/shared/index.ts new file mode 100644 index 000000000..e17ee5c7a --- /dev/null +++ b/client/src/app/+admin/users/shared/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './user.service'; | |||
diff --git a/client/src/app/+admin/users/shared/user.service.ts b/client/src/app/+admin/users/shared/user.service.ts new file mode 100644 index 000000000..d9005b213 --- /dev/null +++ b/client/src/app/+admin/users/shared/user.service.ts | |||
@@ -0,0 +1,49 @@ | |||
1 | import { Injectable } from '@angular/core'; | ||
2 | import 'rxjs/add/operator/catch'; | ||
3 | import 'rxjs/add/operator/map'; | ||
4 | |||
5 | import { AuthHttp, RestExtractor, ResultList, User } from '../../../shared'; | ||
6 | |||
7 | @Injectable() | ||
8 | export class UserService { | ||
9 | // TODO: merge this constant with account | ||
10 | private static BASE_USERS_URL = '/api/v1/users/'; | ||
11 | |||
12 | constructor( | ||
13 | private authHttp: AuthHttp, | ||
14 | private restExtractor: RestExtractor | ||
15 | ) {} | ||
16 | |||
17 | addUser(username: string, password: string) { | ||
18 | const body = { | ||
19 | username, | ||
20 | password | ||
21 | }; | ||
22 | |||
23 | return this.authHttp.post(UserService.BASE_USERS_URL, body) | ||
24 | .map(this.restExtractor.extractDataBool) | ||
25 | .catch(this.restExtractor.handleError); | ||
26 | } | ||
27 | |||
28 | getUsers() { | ||
29 | return this.authHttp.get(UserService.BASE_USERS_URL) | ||
30 | .map(this.restExtractor.extractDataList) | ||
31 | .map(this.extractUsers) | ||
32 | .catch((res) => this.restExtractor.handleError(res)); | ||
33 | } | ||
34 | |||
35 | removeUser(user: User) { | ||
36 | return this.authHttp.delete(UserService.BASE_USERS_URL + user.id); | ||
37 | } | ||
38 | |||
39 | private extractUsers(result: ResultList) { | ||
40 | const usersJson = result.data; | ||
41 | const totalUsers = result.total; | ||
42 | const users = []; | ||
43 | for (const userJson of usersJson) { | ||
44 | users.push(new User(userJson)); | ||
45 | } | ||
46 | |||
47 | return { users, totalUsers }; | ||
48 | } | ||
49 | } | ||
diff --git a/client/src/app/+admin/users/user-add/index.ts b/client/src/app/+admin/users/user-add/index.ts new file mode 100644 index 000000000..66d5ca04f --- /dev/null +++ b/client/src/app/+admin/users/user-add/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './user-add.component'; | |||
diff --git a/client/src/app/+admin/users/user-add/user-add.component.html b/client/src/app/+admin/users/user-add/user-add.component.html new file mode 100644 index 000000000..9b76c7c1b --- /dev/null +++ b/client/src/app/+admin/users/user-add/user-add.component.html | |||
@@ -0,0 +1,29 @@ | |||
1 | <h3>Add user</h3> | ||
2 | |||
3 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | ||
4 | |||
5 | <form role="form" (ngSubmit)="addUser()" [formGroup]="form"> | ||
6 | <div class="form-group"> | ||
7 | <label for="username">Username</label> | ||
8 | <input | ||
9 | type="text" class="form-control" id="username" placeholder="Username" | ||
10 | formControlName="username" | ||
11 | > | ||
12 | <div *ngIf="formErrors.username" class="alert alert-danger"> | ||
13 | {{ formErrors.username }} | ||
14 | </div> | ||
15 | </div> | ||
16 | |||
17 | <div class="form-group"> | ||
18 | <label for="password">Password</label> | ||
19 | <input | ||
20 | type="password" class="form-control" id="password" placeholder="Password" | ||
21 | formControlName="password" | ||
22 | > | ||
23 | <div *ngIf="formErrors.password" class="alert alert-danger"> | ||
24 | {{ formErrors.password }} | ||
25 | </div> | ||
26 | </div> | ||
27 | |||
28 | <input type="submit" value="Add user" class="btn btn-default" [disabled]="!form.valid"> | ||
29 | </form> | ||
diff --git a/client/src/app/+admin/users/user-add/user-add.component.ts b/client/src/app/+admin/users/user-add/user-add.component.ts new file mode 100644 index 000000000..ab96fb01d --- /dev/null +++ b/client/src/app/+admin/users/user-add/user-add.component.ts | |||
@@ -0,0 +1,57 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | ||
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | ||
3 | import { Router } from '@angular/router'; | ||
4 | |||
5 | import { UserService } from '../shared'; | ||
6 | import { FormReactive, USER_USERNAME, USER_PASSWORD } from '../../../shared'; | ||
7 | |||
8 | @Component({ | ||
9 | selector: 'my-user-add', | ||
10 | templateUrl: './user-add.component.html' | ||
11 | }) | ||
12 | export class UserAddComponent extends FormReactive implements OnInit { | ||
13 | error: string = null; | ||
14 | |||
15 | form: FormGroup; | ||
16 | formErrors = { | ||
17 | 'username': '', | ||
18 | 'password': '' | ||
19 | }; | ||
20 | validationMessages = { | ||
21 | 'username': USER_USERNAME.MESSAGES, | ||
22 | 'password': USER_PASSWORD.MESSAGES, | ||
23 | }; | ||
24 | |||
25 | constructor( | ||
26 | private formBuilder: FormBuilder, | ||
27 | private router: Router, | ||
28 | private userService: UserService | ||
29 | ) { | ||
30 | super(); | ||
31 | } | ||
32 | |||
33 | buildForm() { | ||
34 | this.form = this.formBuilder.group({ | ||
35 | username: [ '', USER_USERNAME.VALIDATORS ], | ||
36 | password: [ '', USER_PASSWORD.VALIDATORS ], | ||
37 | }); | ||
38 | |||
39 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | ||
40 | } | ||
41 | |||
42 | ngOnInit() { | ||
43 | this.buildForm(); | ||
44 | } | ||
45 | |||
46 | addUser() { | ||
47 | this.error = null; | ||
48 | |||
49 | const { username, password } = this.form.value; | ||
50 | |||
51 | this.userService.addUser(username, password).subscribe( | ||
52 | ok => this.router.navigate([ '/admin/users/list' ]), | ||
53 | |||
54 | err => this.error = err.text | ||
55 | ); | ||
56 | } | ||
57 | } | ||
diff --git a/client/src/app/+admin/users/user-list/index.ts b/client/src/app/+admin/users/user-list/index.ts new file mode 100644 index 000000000..51fbefa80 --- /dev/null +++ b/client/src/app/+admin/users/user-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './user-list.component'; | |||
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 new file mode 100644 index 000000000..36193d119 --- /dev/null +++ b/client/src/app/+admin/users/user-list/user-list.component.html | |||
@@ -0,0 +1,28 @@ | |||
1 | <h3>Users list</h3> | ||
2 | |||
3 | <table class="table table-hover"> | ||
4 | <thead> | ||
5 | <tr> | ||
6 | <th class="table-column-id">ID</th> | ||
7 | <th>Username</th> | ||
8 | <th>Created Date</th> | ||
9 | <th class="text-right">Remove</th> | ||
10 | </tr> | ||
11 | </thead> | ||
12 | |||
13 | <tbody> | ||
14 | <tr *ngFor="let user of users"> | ||
15 | <td>{{ user.id }}</td> | ||
16 | <td>{{ user.username }}</td> | ||
17 | <td>{{ user.createdAt | date: 'medium' }}</td> | ||
18 | <td class="text-right"> | ||
19 | <span class="glyphicon glyphicon-remove" *ngIf="!user.isAdmin()" (click)="removeUser(user)"></span> | ||
20 | </td> | ||
21 | </tr> | ||
22 | </tbody> | ||
23 | </table> | ||
24 | |||
25 | <a class="add-user btn btn-success pull-right" [routerLink]="['/admin/users/add']"> | ||
26 | <span class="glyphicon glyphicon-plus"></span> | ||
27 | Add user | ||
28 | </a> | ||
diff --git a/client/src/app/+admin/users/user-list/user-list.component.scss b/client/src/app/+admin/users/user-list/user-list.component.scss new file mode 100644 index 000000000..e9f61e900 --- /dev/null +++ b/client/src/app/+admin/users/user-list/user-list.component.scss | |||
@@ -0,0 +1,7 @@ | |||
1 | .glyphicon-remove { | ||
2 | cursor: pointer; | ||
3 | } | ||
4 | |||
5 | .add-user { | ||
6 | margin-top: 10px; | ||
7 | } | ||
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 new file mode 100644 index 000000000..03f4e5c0a --- /dev/null +++ b/client/src/app/+admin/users/user-list/user-list.component.ts | |||
@@ -0,0 +1,42 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | ||
2 | |||
3 | import { User } from '../../../shared'; | ||
4 | import { UserService } from '../shared'; | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-user-list', | ||
8 | templateUrl: './user-list.component.html', | ||
9 | styleUrls: [ './user-list.component.scss' ] | ||
10 | }) | ||
11 | export class UserListComponent implements OnInit { | ||
12 | totalUsers: number; | ||
13 | users: User[]; | ||
14 | |||
15 | constructor(private userService: UserService) {} | ||
16 | |||
17 | ngOnInit() { | ||
18 | this.getUsers(); | ||
19 | } | ||
20 | |||
21 | getUsers() { | ||
22 | this.userService.getUsers().subscribe( | ||
23 | ({ users, totalUsers }) => { | ||
24 | this.users = users; | ||
25 | this.totalUsers = totalUsers; | ||
26 | }, | ||
27 | |||
28 | err => alert(err.text) | ||
29 | ); | ||
30 | } | ||
31 | |||
32 | |||
33 | removeUser(user: User) { | ||
34 | if (confirm('Are you sure?')) { | ||
35 | this.userService.removeUser(user).subscribe( | ||
36 | () => this.getUsers(), | ||
37 | |||
38 | err => alert(err.text) | ||
39 | ); | ||
40 | } | ||
41 | } | ||
42 | } | ||
diff --git a/client/src/app/+admin/users/users.component.ts b/client/src/app/+admin/users/users.component.ts new file mode 100644 index 000000000..37e3b158d --- /dev/null +++ b/client/src/app/+admin/users/users.component.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { Component } from '@angular/core'; | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | |||
7 | export class UsersComponent { | ||
8 | } | ||
diff --git a/client/src/app/+admin/users/users.routes.ts b/client/src/app/+admin/users/users.routes.ts new file mode 100644 index 000000000..92e3e43e3 --- /dev/null +++ b/client/src/app/+admin/users/users.routes.ts | |||
@@ -0,0 +1,37 @@ | |||
1 | import { Routes } from '@angular/router'; | ||
2 | |||
3 | import { UsersComponent } from './users.component'; | ||
4 | import { UserAddComponent } from './user-add'; | ||
5 | import { UserListComponent } from './user-list'; | ||
6 | |||
7 | export const UsersRoutes: Routes = [ | ||
8 | { | ||
9 | path: 'users', | ||
10 | component: UsersComponent, | ||
11 | children: [ | ||
12 | { | ||
13 | path: '', | ||
14 | redirectTo: 'list', | ||
15 | pathMatch: 'full' | ||
16 | }, | ||
17 | { | ||
18 | path: 'list', | ||
19 | component: UserListComponent, | ||
20 | data: { | ||
21 | meta: { | ||
22 | titleSuffix: ' - Users list' | ||
23 | } | ||
24 | } | ||
25 | }, | ||
26 | { | ||
27 | path: 'add', | ||
28 | component: UserAddComponent, | ||
29 | data: { | ||
30 | meta: { | ||
31 | titleSuffix: ' - Add a user' | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | ] | ||
36 | } | ||
37 | ]; | ||
diff --git a/client/src/app/+admin/video-abuses/index.ts b/client/src/app/+admin/video-abuses/index.ts new file mode 100644 index 000000000..7f5e65f91 --- /dev/null +++ b/client/src/app/+admin/video-abuses/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './video-abuse-list'; | ||
2 | export * from './video-abuses.component'; | ||
3 | export * from './video-abuses.routes'; | ||
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/index.ts b/client/src/app/+admin/video-abuses/video-abuse-list/index.ts new file mode 100644 index 000000000..3f2ed1714 --- /dev/null +++ b/client/src/app/+admin/video-abuses/video-abuse-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './video-abuse-list.component'; | |||
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 new file mode 100644 index 000000000..46043577c --- /dev/null +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html | |||
@@ -0,0 +1,27 @@ | |||
1 | <h3>Video abuses list</h3> | ||
2 | |||
3 | <table class="table table-hover"> | ||
4 | <thead> | ||
5 | <tr> | ||
6 | <th class="cell-id">ID</th> | ||
7 | <th class="cell-reason">Reason</th> | ||
8 | <th>Reporter pod host</th> | ||
9 | <th>Reporter username</th> | ||
10 | <th>Video</th> | ||
11 | <th>Created at</th> | ||
12 | </tr> | ||
13 | </thead> | ||
14 | |||
15 | <tbody> | ||
16 | <tr *ngFor="let videoAbuse of videoAbuses"> | ||
17 | <td>{{ videoAbuse.id }}</td> | ||
18 | <td>{{ videoAbuse.reason }}</td> | ||
19 | <td>{{ videoAbuse.reporterPodHost }}</td> | ||
20 | <td>{{ videoAbuse.reporterUsername }}</td> | ||
21 | <td> | ||
22 | <a [routerLink]="buildVideoLink(videoAbuse)" title="Go to video">{{ videoAbuse.videoId }}</a> | ||
23 | </td> | ||
24 | <td>{{ videoAbuse.createdAt | date: 'medium' }}</td> | ||
25 | </tr> | ||
26 | </tbody> | ||
27 | </table> | ||
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss new file mode 100644 index 000000000..a094f74b8 --- /dev/null +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.scss | |||
@@ -0,0 +1,7 @@ | |||
1 | .cell-id { | ||
2 | width: 40px; | ||
3 | } | ||
4 | |||
5 | .cell-reason { | ||
6 | width: 200px; | ||
7 | } | ||
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 new file mode 100644 index 000000000..de58bba3d --- /dev/null +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts | |||
@@ -0,0 +1,31 @@ | |||
1 | import { setInterval } from 'timers' | ||
2 | import { Component, OnInit } from '@angular/core'; | ||
3 | |||
4 | import { VideoAbuseService, VideoAbuse} from '../../../shared'; | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-video-abuse-list', | ||
8 | templateUrl: './video-abuse-list.component.html', | ||
9 | styleUrls: [ './video-abuse-list.component.scss' ] | ||
10 | }) | ||
11 | export class VideoAbuseListComponent implements OnInit { | ||
12 | videoAbuses: VideoAbuse[]; | ||
13 | |||
14 | constructor(private videoAbuseService: VideoAbuseService) { } | ||
15 | |||
16 | ngOnInit() { | ||
17 | this.getVideoAbuses(); | ||
18 | } | ||
19 | |||
20 | buildVideoLink(videoAbuse: VideoAbuse) { | ||
21 | return `/videos/${videoAbuse.videoId}`; | ||
22 | } | ||
23 | |||
24 | private getVideoAbuses() { | ||
25 | this.videoAbuseService.getVideoAbuses().subscribe( | ||
26 | res => this.videoAbuses = res.videoAbuses, | ||
27 | |||
28 | err => alert(err.text) | ||
29 | ); | ||
30 | } | ||
31 | } | ||
diff --git a/client/src/app/+admin/video-abuses/video-abuses.component.ts b/client/src/app/+admin/video-abuses/video-abuses.component.ts new file mode 100644 index 000000000..001f27e87 --- /dev/null +++ b/client/src/app/+admin/video-abuses/video-abuses.component.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { Component } from '@angular/core'; | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | |||
7 | export class VideoAbusesComponent { | ||
8 | } | ||
diff --git a/client/src/app/+admin/video-abuses/video-abuses.routes.ts b/client/src/app/+admin/video-abuses/video-abuses.routes.ts new file mode 100644 index 000000000..26a761887 --- /dev/null +++ b/client/src/app/+admin/video-abuses/video-abuses.routes.ts | |||
@@ -0,0 +1,28 @@ | |||
1 | import { Routes } from '@angular/router'; | ||
2 | |||
3 | import { VideoAbusesComponent } from './video-abuses.component'; | ||
4 | import { VideoAbuseListComponent } from './video-abuse-list'; | ||
5 | |||
6 | export const VideoAbusesRoutes: Routes = [ | ||
7 | { | ||
8 | path: 'video-abuses', | ||
9 | component: VideoAbusesComponent | ||
10 | , | ||
11 | children: [ | ||
12 | { | ||
13 | path: '', | ||
14 | redirectTo: 'list', | ||
15 | pathMatch: 'full' | ||
16 | }, | ||
17 | { | ||
18 | path: 'list', | ||
19 | component: VideoAbuseListComponent, | ||
20 | data: { | ||
21 | meta: { | ||
22 | titleSuffix: ' - Video abuses list' | ||
23 | } | ||
24 | } | ||
25 | } | ||
26 | ] | ||
27 | } | ||
28 | ]; | ||