*/
const AssetsPlugin = require('assets-webpack-plugin')
+const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin')
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin')
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
disabled: !AOT,
tsConfig: helpers.root('tsconfig.webpack.json'),
resourceOverride: helpers.root('config/resource-override.js')
+ }),
+
+ new BundleAnalyzerPlugin({
+ // Can be `server`, `static` or `disabled`.
+ // In `server` mode analyzer will start HTTP server to show bundle report.
+ // In `static` mode single HTML file with bundle report will be generated.
+ // In `disabled` mode you can use this plugin to just generate Webpack Stats JSON file by setting `generateStatsFile` to `true`.
+ analyzerMode: 'static',
+ // Path to bundle report file that will be generated in `static` mode.
+ // Relative to bundles output directory.
+ reportFilename: 'report.html',
+ // Automatically open report in default browser
+ openAnalyzer: false,
+ // If `true`, Webpack Stats JSON file will be generated in bundles output directory
+ generateStatsFile: true,
+ // Name of Webpack Stats JSON file that will be generated if `generateStatsFile` is `true`.
+ // Relative to bundles output directory.
+ statsFilename: 'stats.json',
+ // Options for `stats.toJson()` method.
+ // For example you can exclude sources of your modules from stats file with `source: false` option.
+ // See more options here: https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
+ statsOptions: null,
+ // Log level. Can be 'info', 'warn', 'error' or 'silent'.
+ logLevel: 'info'
})
],
"add-asset-html-webpack-plugin": "^1.0.2",
"codelyzer": "2.0.0-beta.4",
"standard": "^8.0.0",
+ "webpack-bundle-analyzer": "^2.2.1",
"webpack-dll-bundles-plugin": "^1.0.0-beta.5"
}
}
--- /dev/null
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { AdminComponent } from './admin.component';
+import { FriendsRoutes } from './friends';
+import { RequestsRoutes } from './requests';
+import { UsersRoutes } from './users';
+import { VideoAbusesRoutes } from './video-abuses';
+
+const adminRoutes: Routes = [
+ {
+ path: '',
+ component: AdminComponent,
+ children: [
+ {
+ path: '',
+ redirectTo: 'users',
+ pathMatch: 'full'
+ },
+ ...FriendsRoutes,
+ ...RequestsRoutes,
+ ...UsersRoutes,
+ ...VideoAbusesRoutes
+ ]
+ }
+];
+
+@NgModule({
+ imports: [ RouterModule.forChild(adminRoutes) ],
+ exports: [ RouterModule ]
+})
+export class AdminRoutingModule {}
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ template: '<router-outlet></router-outlet>'
+})
+
+export class AdminComponent {
+}
--- /dev/null
+import { NgModule } from '@angular/core';
+
+import { AdminComponent } from './admin.component';
+import { AdminRoutingModule } from './admin-routing.module';
+import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends';
+import { RequestsComponent, RequestStatsComponent, RequestService } from './requests';
+import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users';
+import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses';
+import { SharedModule } from '../shared';
+
+@NgModule({
+ imports: [
+ AdminRoutingModule,
+ SharedModule
+ ],
+
+ declarations: [
+ AdminComponent,
+
+ FriendsComponent,
+ FriendAddComponent,
+ FriendListComponent,
+
+ RequestsComponent,
+ RequestStatsComponent,
+
+ UsersComponent,
+ UserAddComponent,
+ UserListComponent,
+
+ VideoAbusesComponent,
+ VideoAbuseListComponent
+ ],
+
+ exports: [
+ AdminComponent
+ ],
+
+ providers: [
+ FriendService,
+ RequestService,
+ UserService
+ ]
+})
+export class AdminModule { }
--- /dev/null
+<h3>Make friends</h3>
+
+<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
+
+<form (ngSubmit)="makeFriends()" [formGroup]="form">
+ <div class="form-group" *ngFor="let host of hosts; let id = index; trackBy:customTrackBy">
+ <label for="username">Host</label>
+
+ <div class="input-group">
+ <input
+ type="text" class="form-control" placeholder="domain.tld"
+ [id]="'host-' + id" [formControlName]="'host-' + id"
+ />
+ <span class="input-group-btn">
+ <button *ngIf="displayAddField(id)" (click)="addField()" class="btn btn-default" type="button">+</button>
+ <button *ngIf="displayRemoveField(id)" (click)="removeField(id)" class="btn btn-default" type="button">-</button>
+ </span>
+ </div>
+
+ <div [hidden]="form.controls['host-' + id].valid || form.controls['host-' + id].pristine" class="alert alert-warning">
+ It should be a valid host.
+ </div>
+ </div>
+
+ <div *ngIf="canMakeFriends() === false" class="alert alert-warning">
+ It seems that you are not on a HTTPS pod. Your webserver need to have TLS activated in order to make friends.
+ </div>
+
+ <input type="submit" value="Make friends" class="btn btn-default" [disabled]="!isFormValid()">
+</form>
--- /dev/null
+table {
+ margin-bottom: 40px;
+}
+
+.input-group-btn button {
+ width: 35px;
+}
--- /dev/null
+import { Component, OnInit } from '@angular/core';
+import { FormControl, FormGroup } from '@angular/forms';
+import { Router } from '@angular/router';
+
+import { validateHost } from '../../../shared';
+import { FriendService } from '../shared';
+
+@Component({
+ selector: 'my-friend-add',
+ templateUrl: './friend-add.component.html',
+ styleUrls: [ './friend-add.component.scss' ]
+})
+export class FriendAddComponent implements OnInit {
+ form: FormGroup;
+ hosts = [ ];
+ error: string = null;
+
+ constructor(private router: Router, private friendService: FriendService) {}
+
+ ngOnInit() {
+ this.form = new FormGroup({});
+ this.addField();
+ }
+
+ addField() {
+ this.form.addControl(`host-${this.hosts.length}`, new FormControl('', [ validateHost ]));
+ this.hosts.push('');
+ }
+
+ canMakeFriends() {
+ return window.location.protocol === 'https:';
+ }
+
+ customTrackBy(index: number, obj: any): any {
+ return index;
+ }
+
+ displayAddField(index: number) {
+ return index === (this.hosts.length - 1);
+ }
+
+ displayRemoveField(index: number) {
+ return (index !== 0 || this.hosts.length > 1) && index !== (this.hosts.length - 1);
+ }
+
+ isFormValid() {
+ // Do not check the last input
+ for (let i = 0; i < this.hosts.length - 1; i++) {
+ if (!this.form.controls[`host-${i}`].valid) return false;
+ }
+
+ const lastIndex = this.hosts.length - 1;
+ // If the last input (which is not the first) is empty, it's ok
+ if (this.hosts[lastIndex] === '' && lastIndex !== 0) {
+ return true;
+ } else {
+ return this.form.controls[`host-${lastIndex}`].valid;
+ }
+ }
+
+ removeField(index: number) {
+ // Remove the last control
+ this.form.removeControl(`host-${this.hosts.length - 1}`);
+ this.hosts.splice(index, 1);
+ }
+
+ makeFriends() {
+ this.error = '';
+
+ const notEmptyHosts = this.getNotEmptyHosts();
+ if (notEmptyHosts.length === 0) {
+ this.error = 'You need to specify at least 1 host.';
+ return;
+ }
+
+ if (!this.isHostsUnique(notEmptyHosts)) {
+ this.error = 'Hosts need to be unique.';
+ return;
+ }
+
+ const confirmMessage = 'Are you sure to make friends with:\n - ' + notEmptyHosts.join('\n - ');
+ if (!confirm(confirmMessage)) return;
+
+ this.friendService.makeFriends(notEmptyHosts).subscribe(
+ status => {
+ alert('Make friends request sent!');
+ this.router.navigate([ '/admin/friends/list' ]);
+ },
+ error => alert(error.text)
+ );
+ }
+
+ private getNotEmptyHosts() {
+ const notEmptyHosts = [];
+
+ Object.keys(this.form.value).forEach((hostKey) => {
+ const host = this.form.value[hostKey];
+ if (host !== '') notEmptyHosts.push(host);
+ });
+
+ return notEmptyHosts;
+ }
+
+ private isHostsUnique(hosts: string[]) {
+ return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host));
+ }
+}
--- /dev/null
+export * from './friend-add.component';
--- /dev/null
+<h3>Friends list</h3>
+
+<table class="table table-hover">
+ <thead>
+ <tr>
+ <th class="table-column-id">ID</th>
+ <th>Host</th>
+ <th>Score</th>
+ <th>Created Date</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <tr *ngFor="let friend of friends">
+ <td>{{ friend.id }}</td>
+ <td>{{ friend.host }}</td>
+ <td>{{ friend.score }}</td>
+ <td>{{ friend.createdAt | date: 'medium' }}</td>
+ </tr>
+ </tbody>
+</table>
+
+<a *ngIf="friends && friends.length !== 0" class="add-user btn btn-danger pull-left" (click)="quitFriends()">
+ Quit friends
+</a>
+
+<a *ngIf="friends?.length === 0" class="add-user btn btn-success pull-right" [routerLink]="['/admin/friends/add']">
+ Make friends
+</a>
--- /dev/null
+table {
+ margin-bottom: 40px;
+}
--- /dev/null
+import { Component, OnInit } from '@angular/core';
+
+import { Friend, FriendService } from '../shared';
+
+@Component({
+ selector: 'my-friend-list',
+ templateUrl: './friend-list.component.html',
+ styleUrls: [ './friend-list.component.scss' ]
+})
+export class FriendListComponent implements OnInit {
+ friends: Friend[];
+
+ constructor(private friendService: FriendService) { }
+
+ ngOnInit() {
+ this.getFriends();
+ }
+
+ quitFriends() {
+ if (!confirm('Are you sure?')) return;
+
+ this.friendService.quitFriends().subscribe(
+ status => {
+ alert('Quit friends!');
+ this.getFriends();
+ },
+ error => alert(error.text)
+ );
+ }
+
+ private getFriends() {
+ this.friendService.getFriends().subscribe(
+ res => this.friends = res.friends,
+
+ err => alert(err.text)
+ );
+ }
+}
--- /dev/null
+export * from './friend-list.component';
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ template: '<router-outlet></router-outlet>'
+})
+
+export class FriendsComponent {
+}
--- /dev/null
+import { Routes } from '@angular/router';
+
+import { FriendsComponent } from './friends.component';
+import { FriendAddComponent } from './friend-add';
+import { FriendListComponent } from './friend-list';
+
+export const FriendsRoutes: Routes = [
+ {
+ path: 'friends',
+ component: FriendsComponent,
+ children: [
+ {
+ path: '',
+ redirectTo: 'list',
+ pathMatch: 'full'
+ },
+ {
+ path: 'list',
+ component: FriendListComponent,
+ data: {
+ meta: {
+ titleSuffix: ' - Friends list'
+ }
+ }
+ },
+ {
+ path: 'add',
+ component: FriendAddComponent,
+ data: {
+ meta: {
+ titleSuffix: ' - Add friends'
+ }
+ }
+ }
+ ]
+ }
+];
--- /dev/null
+export * from './friend-add';
+export * from './friend-list';
+export * from './shared';
+export * from './friends.component';
+export * from './friends.routes';
--- /dev/null
+export interface Friend {
+ id: string;
+ host: string;
+ score: number;
+ createdAt: Date;
+}
--- /dev/null
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/map';
+
+import { Friend } from './friend.model';
+import { AuthHttp, RestExtractor, ResultList } from '../../../shared';
+
+@Injectable()
+export class FriendService {
+ private static BASE_FRIEND_URL: string = '/api/v1/pods/';
+
+ constructor (
+ private authHttp: AuthHttp,
+ private restExtractor: RestExtractor
+ ) {}
+
+ getFriends() {
+ return this.authHttp.get(FriendService.BASE_FRIEND_URL)
+ .map(this.restExtractor.extractDataList)
+ .map(this.extractFriends)
+ .catch((res) => this.restExtractor.handleError(res));
+ }
+
+ makeFriends(notEmptyHosts) {
+ const body = {
+ hosts: notEmptyHosts
+ };
+
+ return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'makefriends', body)
+ .map(this.restExtractor.extractDataBool)
+ .catch((res) => this.restExtractor.handleError(res));
+ }
+
+ quitFriends() {
+ return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quitfriends')
+ .map(res => res.status)
+ .catch((res) => this.restExtractor.handleError(res));
+ }
+
+ private extractFriends(result: ResultList) {
+ const friends: Friend[] = result.data;
+ const totalFriends = result.total;
+
+ return { friends, totalFriends };
+ }
+}
--- /dev/null
+export * from './friend.model';
+export * from './friend.service';
--- /dev/null
+export * from './friends';
+export * from './requests';
+export * from './users';
+export * from './admin-routing.module';
+export * from './admin.module';
+export * from './admin.component';
--- /dev/null
+export * from './request-stats';
+export * from './shared';
+export * from './requests.component';
+export * from './requests.routes';
--- /dev/null
+export * from './request-stats.component';
--- /dev/null
+<h3>Requests stats</h3>
+
+<div *ngIf="stats !== null">
+ <div class="requests-general">
+ <div>
+ <span class="label-description">Remaining requests:</span>
+ {{ stats.totalRequests }}
+ </div>
+
+ <div>
+ <span class="label-description">Interval seconds between requests:</span>
+ {{ stats.secondsInterval }}
+ </div>
+
+ <div>
+ <span class="label-description">Remaining time before the scheduled request:</span>
+ {{ stats.remainingSeconds }}
+ </div>
+ </div>
+
+ <div class="requests-limit">
+ <div>
+ <span class="label-description">Maximum number of different pods for a scheduled request:</span>
+ {{ stats.requestsLimitPods }}
+ </div>
+
+ <div>
+ <span class="label-description">Maximum number of requests per pod for a scheduled request:</span>
+ {{ stats.requestsLimitPerPod }}
+ </div>
+ </div>
+
+</div>
--- /dev/null
+.label-description {
+ display: inline-block;
+ font-weight: bold;
+ color: black;
+}
+
+.requests-general {
+ .label-description {
+ width: 320px;
+ }
+}
+
+.requests-limit {
+ margin-top: 20px;
+
+ .label-description {
+ width: 430px;
+ }
+}
--- /dev/null
+import { setInterval } from 'timers'
+import { Component, OnInit, OnDestroy } from '@angular/core';
+
+import { RequestService, RequestStats } from '../shared';
+
+@Component({
+ selector: 'my-request-stats',
+ templateUrl: './request-stats.component.html',
+ styleUrls: [ './request-stats.component.scss' ]
+})
+export class RequestStatsComponent implements OnInit, OnDestroy {
+ stats: RequestStats = null;
+
+ private interval: NodeJS.Timer = null;
+
+ constructor(private requestService: RequestService) { }
+
+ ngOnInit() {
+ this.getStats();
+ this.runInterval();
+ }
+
+ ngOnDestroy() {
+ if (this.stats !== null && this.stats.secondsInterval !== null) {
+ clearInterval(this.interval);
+ }
+ }
+
+ getStats() {
+ this.requestService.getStats().subscribe(
+ stats => this.stats = stats,
+
+ err => alert(err.text)
+ );
+ }
+
+ private runInterval() {
+ this.interval = setInterval(() => {
+ this.stats.remainingMilliSeconds -= 1000;
+
+ if (this.stats.remainingMilliSeconds <= 0) {
+ setTimeout(() => this.getStats(), this.stats.remainingMilliSeconds + 100);
+ }
+ }, 1000);
+ }
+
+
+}
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ template: '<router-outlet></router-outlet>'
+})
+
+export class RequestsComponent {
+}
--- /dev/null
+import { Routes } from '@angular/router';
+
+import { RequestsComponent } from './requests.component';
+import { RequestStatsComponent } from './request-stats';
+
+export const RequestsRoutes: Routes = [
+ {
+ path: 'requests',
+ component: RequestsComponent,
+ children: [
+ {
+ path: '',
+ redirectTo: 'stats',
+ pathMatch: 'full'
+ },
+ {
+ path: 'stats',
+ component: RequestStatsComponent,
+ data: {
+ meta: {
+ titleSuffix: ' - Request stats'
+ }
+ }
+ }
+ ]
+ }
+];
--- /dev/null
+export * from './request-stats.model';
+export * from './request.service';
--- /dev/null
+export interface Request {
+ request: any;
+ to: any;
+}
+
+export class RequestStats {
+ requestsLimitPods: number;
+ requestsLimitPerPod: number;
+ milliSecondsInterval: number;
+ remainingMilliSeconds: number;
+ totalRequests: number;
+
+ constructor(hash: {
+ requestsLimitPods: number,
+ requestsLimitPerPod: number,
+ milliSecondsInterval: number,
+ remainingMilliSeconds: number,
+ totalRequests: number;
+ }) {
+ this.requestsLimitPods = hash.requestsLimitPods;
+ this.requestsLimitPerPod = hash.requestsLimitPerPod;
+ this.milliSecondsInterval = hash.milliSecondsInterval;
+ this.remainingMilliSeconds = hash.remainingMilliSeconds;
+ this.totalRequests = hash.totalRequests;
+ }
+
+ get remainingSeconds() {
+ return Math.floor(this.remainingMilliSeconds / 1000);
+ }
+
+ get secondsInterval() {
+ return Math.floor(this.milliSecondsInterval / 1000);
+ }
+
+}
--- /dev/null
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/map';
+
+import { RequestStats } from './request-stats.model';
+import { AuthHttp, RestExtractor } from '../../../shared';
+
+@Injectable()
+export class RequestService {
+ private static BASE_REQUEST_URL: string = '/api/v1/requests/';
+
+ constructor (
+ private authHttp: AuthHttp,
+ private restExtractor: RestExtractor
+ ) {}
+
+ getStats(): Observable<RequestStats> {
+ return this.authHttp.get(RequestService.BASE_REQUEST_URL + 'stats')
+ .map(this.restExtractor.extractDataGet)
+ .map((data) => new RequestStats(data))
+ .catch((res) => this.restExtractor.handleError(res));
+ }
+}
--- /dev/null
+export * from './shared';
+export * from './user-add';
+export * from './user-list';
+export * from './users.component';
+export * from './users.routes';
--- /dev/null
+export * from './user.service';
--- /dev/null
+import { Injectable } from '@angular/core';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/map';
+
+import { AuthHttp, RestExtractor, ResultList, User } from '../../../shared';
+
+@Injectable()
+export class UserService {
+ // TODO: merge this constant with account
+ private static BASE_USERS_URL = '/api/v1/users/';
+
+ constructor(
+ private authHttp: AuthHttp,
+ private restExtractor: RestExtractor
+ ) {}
+
+ addUser(username: string, password: string) {
+ const body = {
+ username,
+ password
+ };
+
+ return this.authHttp.post(UserService.BASE_USERS_URL, body)
+ .map(this.restExtractor.extractDataBool)
+ .catch(this.restExtractor.handleError);
+ }
+
+ getUsers() {
+ return this.authHttp.get(UserService.BASE_USERS_URL)
+ .map(this.restExtractor.extractDataList)
+ .map(this.extractUsers)
+ .catch((res) => this.restExtractor.handleError(res));
+ }
+
+ removeUser(user: User) {
+ return this.authHttp.delete(UserService.BASE_USERS_URL + user.id);
+ }
+
+ private extractUsers(result: ResultList) {
+ const usersJson = result.data;
+ const totalUsers = result.total;
+ const users = [];
+ for (const userJson of usersJson) {
+ users.push(new User(userJson));
+ }
+
+ return { users, totalUsers };
+ }
+}
--- /dev/null
+export * from './user-add.component';
--- /dev/null
+<h3>Add user</h3>
+
+<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
+
+<form role="form" (ngSubmit)="addUser()" [formGroup]="form">
+ <div class="form-group">
+ <label for="username">Username</label>
+ <input
+ type="text" class="form-control" id="username" placeholder="Username"
+ formControlName="username"
+ >
+ <div *ngIf="formErrors.username" class="alert alert-danger">
+ {{ formErrors.username }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="password">Password</label>
+ <input
+ type="password" class="form-control" id="password" placeholder="Password"
+ formControlName="password"
+ >
+ <div *ngIf="formErrors.password" class="alert alert-danger">
+ {{ formErrors.password }}
+ </div>
+ </div>
+
+ <input type="submit" value="Add user" class="btn btn-default" [disabled]="!form.valid">
+</form>
--- /dev/null
+import { Component, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { Router } from '@angular/router';
+
+import { UserService } from '../shared';
+import { FormReactive, USER_USERNAME, USER_PASSWORD } from '../../../shared';
+
+@Component({
+ selector: 'my-user-add',
+ templateUrl: './user-add.component.html'
+})
+export class UserAddComponent extends FormReactive implements OnInit {
+ error: string = null;
+
+ form: FormGroup;
+ formErrors = {
+ 'username': '',
+ 'password': ''
+ };
+ validationMessages = {
+ 'username': USER_USERNAME.MESSAGES,
+ 'password': USER_PASSWORD.MESSAGES,
+ };
+
+ constructor(
+ private formBuilder: FormBuilder,
+ private router: Router,
+ private userService: UserService
+ ) {
+ super();
+ }
+
+ buildForm() {
+ this.form = this.formBuilder.group({
+ username: [ '', USER_USERNAME.VALIDATORS ],
+ password: [ '', USER_PASSWORD.VALIDATORS ],
+ });
+
+ this.form.valueChanges.subscribe(data => this.onValueChanged(data));
+ }
+
+ ngOnInit() {
+ this.buildForm();
+ }
+
+ addUser() {
+ this.error = null;
+
+ const { username, password } = this.form.value;
+
+ this.userService.addUser(username, password).subscribe(
+ ok => this.router.navigate([ '/admin/users/list' ]),
+
+ err => this.error = err.text
+ );
+ }
+}
--- /dev/null
+export * from './user-list.component';
--- /dev/null
+<h3>Users list</h3>
+
+<table class="table table-hover">
+ <thead>
+ <tr>
+ <th class="table-column-id">ID</th>
+ <th>Username</th>
+ <th>Created Date</th>
+ <th class="text-right">Remove</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <tr *ngFor="let user of users">
+ <td>{{ user.id }}</td>
+ <td>{{ user.username }}</td>
+ <td>{{ user.createdAt | date: 'medium' }}</td>
+ <td class="text-right">
+ <span class="glyphicon glyphicon-remove" *ngIf="!user.isAdmin()" (click)="removeUser(user)"></span>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<a class="add-user btn btn-success pull-right" [routerLink]="['/admin/users/add']">
+ <span class="glyphicon glyphicon-plus"></span>
+ Add user
+</a>
--- /dev/null
+.glyphicon-remove {
+ cursor: pointer;
+}
+
+.add-user {
+ margin-top: 10px;
+}
--- /dev/null
+import { Component, OnInit } from '@angular/core';
+
+import { User } from '../../../shared';
+import { UserService } from '../shared';
+
+@Component({
+ selector: 'my-user-list',
+ templateUrl: './user-list.component.html',
+ styleUrls: [ './user-list.component.scss' ]
+})
+export class UserListComponent implements OnInit {
+ totalUsers: number;
+ users: User[];
+
+ constructor(private userService: UserService) {}
+
+ ngOnInit() {
+ this.getUsers();
+ }
+
+ getUsers() {
+ this.userService.getUsers().subscribe(
+ ({ users, totalUsers }) => {
+ this.users = users;
+ this.totalUsers = totalUsers;
+ },
+
+ err => alert(err.text)
+ );
+ }
+
+
+ removeUser(user: User) {
+ if (confirm('Are you sure?')) {
+ this.userService.removeUser(user).subscribe(
+ () => this.getUsers(),
+
+ err => alert(err.text)
+ );
+ }
+ }
+}
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ template: '<router-outlet></router-outlet>'
+})
+
+export class UsersComponent {
+}
--- /dev/null
+import { Routes } from '@angular/router';
+
+import { UsersComponent } from './users.component';
+import { UserAddComponent } from './user-add';
+import { UserListComponent } from './user-list';
+
+export const UsersRoutes: Routes = [
+ {
+ path: 'users',
+ component: UsersComponent,
+ children: [
+ {
+ path: '',
+ redirectTo: 'list',
+ pathMatch: 'full'
+ },
+ {
+ path: 'list',
+ component: UserListComponent,
+ data: {
+ meta: {
+ titleSuffix: ' - Users list'
+ }
+ }
+ },
+ {
+ path: 'add',
+ component: UserAddComponent,
+ data: {
+ meta: {
+ titleSuffix: ' - Add a user'
+ }
+ }
+ }
+ ]
+ }
+];
--- /dev/null
+export * from './video-abuse-list';
+export * from './video-abuses.component';
+export * from './video-abuses.routes';
--- /dev/null
+export * from './video-abuse-list.component';
--- /dev/null
+<h3>Video abuses list</h3>
+
+<table class="table table-hover">
+ <thead>
+ <tr>
+ <th class="cell-id">ID</th>
+ <th class="cell-reason">Reason</th>
+ <th>Reporter pod host</th>
+ <th>Reporter username</th>
+ <th>Video</th>
+ <th>Created at</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <tr *ngFor="let videoAbuse of videoAbuses">
+ <td>{{ videoAbuse.id }}</td>
+ <td>{{ videoAbuse.reason }}</td>
+ <td>{{ videoAbuse.reporterPodHost }}</td>
+ <td>{{ videoAbuse.reporterUsername }}</td>
+ <td>
+ <a [routerLink]="buildVideoLink(videoAbuse)" title="Go to video">{{ videoAbuse.videoId }}</a>
+ </td>
+ <td>{{ videoAbuse.createdAt | date: 'medium' }}</td>
+ </tr>
+ </tbody>
+</table>
--- /dev/null
+.cell-id {
+ width: 40px;
+}
+
+.cell-reason {
+ width: 200px;
+}
--- /dev/null
+import { setInterval } from 'timers'
+import { Component, OnInit } from '@angular/core';
+
+import { VideoAbuseService, VideoAbuse} from '../../../shared';
+
+@Component({
+ selector: 'my-video-abuse-list',
+ templateUrl: './video-abuse-list.component.html',
+ styleUrls: [ './video-abuse-list.component.scss' ]
+})
+export class VideoAbuseListComponent implements OnInit {
+ videoAbuses: VideoAbuse[];
+
+ constructor(private videoAbuseService: VideoAbuseService) { }
+
+ ngOnInit() {
+ this.getVideoAbuses();
+ }
+
+ buildVideoLink(videoAbuse: VideoAbuse) {
+ return `/videos/${videoAbuse.videoId}`;
+ }
+
+ private getVideoAbuses() {
+ this.videoAbuseService.getVideoAbuses().subscribe(
+ res => this.videoAbuses = res.videoAbuses,
+
+ err => alert(err.text)
+ );
+ }
+}
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ template: '<router-outlet></router-outlet>'
+})
+
+export class VideoAbusesComponent {
+}
--- /dev/null
+import { Routes } from '@angular/router';
+
+import { VideoAbusesComponent } from './video-abuses.component';
+import { VideoAbuseListComponent } from './video-abuse-list';
+
+export const VideoAbusesRoutes: Routes = [
+ {
+ path: 'video-abuses',
+ component: VideoAbusesComponent
+ ,
+ children: [
+ {
+ path: '',
+ redirectTo: 'list',
+ pathMatch: 'full'
+ },
+ {
+ path: 'list',
+ component: VideoAbuseListComponent,
+ data: {
+ meta: {
+ titleSuffix: ' - Video abuses list'
+ }
+ }
+ }
+ ]
+ }
+];
+++ /dev/null
-import { NgModule } from '@angular/core';
-import { RouterModule, Routes } from '@angular/router';
-
-import { AdminComponent } from './admin.component';
-import { FriendsRoutes } from './friends';
-import { RequestsRoutes } from './requests';
-import { UsersRoutes } from './users';
-import { VideoAbusesRoutes } from './video-abuses';
-
-const adminRoutes: Routes = [
- {
- path: 'admin',
- component: AdminComponent,
- children: [
- {
- path: '',
- redirectTo: 'users',
- pathMatch: 'full'
- },
- ...FriendsRoutes,
- ...RequestsRoutes,
- ...UsersRoutes,
- ...VideoAbusesRoutes
- ]
- }
-];
-
-@NgModule({
- imports: [ RouterModule.forChild(adminRoutes) ],
- exports: [ RouterModule ]
-})
-export class AdminRoutingModule {}
+++ /dev/null
-import { Component } from '@angular/core';
-
-@Component({
- template: '<router-outlet></router-outlet>'
-})
-
-export class AdminComponent {
-}
+++ /dev/null
-import { NgModule } from '@angular/core';
-
-import { AdminComponent } from './admin.component';
-import { AdminRoutingModule } from './admin-routing.module';
-import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendService } from './friends';
-import { RequestsComponent, RequestStatsComponent, RequestService } from './requests';
-import { UsersComponent, UserAddComponent, UserListComponent, UserService } from './users';
-import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses';
-import { MenuAdminComponent } from './menu-admin.component';
-import { SharedModule } from '../shared';
-
-@NgModule({
- imports: [
- AdminRoutingModule,
- SharedModule
- ],
-
- declarations: [
- AdminComponent,
-
- FriendsComponent,
- FriendAddComponent,
- FriendListComponent,
-
- RequestsComponent,
- RequestStatsComponent,
-
- UsersComponent,
- UserAddComponent,
- UserListComponent,
-
- VideoAbusesComponent,
- VideoAbuseListComponent,
-
- MenuAdminComponent
- ],
-
- exports: [
- AdminComponent,
- MenuAdminComponent
- ],
-
- providers: [
- FriendService,
- RequestService,
- UserService
- ]
-})
-export class AdminModule { }
+++ /dev/null
-<h3>Make friends</h3>
-
-<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
-
-<form (ngSubmit)="makeFriends()" [formGroup]="form">
- <div class="form-group" *ngFor="let host of hosts; let id = index; trackBy:customTrackBy">
- <label for="username">Host</label>
-
- <div class="input-group">
- <input
- type="text" class="form-control" placeholder="domain.tld"
- [id]="'host-' + id" [formControlName]="'host-' + id"
- />
- <span class="input-group-btn">
- <button *ngIf="displayAddField(id)" (click)="addField()" class="btn btn-default" type="button">+</button>
- <button *ngIf="displayRemoveField(id)" (click)="removeField(id)" class="btn btn-default" type="button">-</button>
- </span>
- </div>
-
- <div [hidden]="form.controls['host-' + id].valid || form.controls['host-' + id].pristine" class="alert alert-warning">
- It should be a valid host.
- </div>
- </div>
-
- <div *ngIf="canMakeFriends() === false" class="alert alert-warning">
- It seems that you are not on a HTTPS pod. Your webserver need to have TLS activated in order to make friends.
- </div>
-
- <input type="submit" value="Make friends" class="btn btn-default" [disabled]="!isFormValid()">
-</form>
+++ /dev/null
-table {
- margin-bottom: 40px;
-}
-
-.input-group-btn button {
- width: 35px;
-}
+++ /dev/null
-import { Component, OnInit } from '@angular/core';
-import { FormControl, FormGroup } from '@angular/forms';
-import { Router } from '@angular/router';
-
-import { validateHost } from '../../../shared';
-import { FriendService } from '../shared';
-
-@Component({
- selector: 'my-friend-add',
- templateUrl: './friend-add.component.html',
- styleUrls: [ './friend-add.component.scss' ]
-})
-export class FriendAddComponent implements OnInit {
- form: FormGroup;
- hosts = [ ];
- error: string = null;
-
- constructor(private router: Router, private friendService: FriendService) {}
-
- ngOnInit() {
- this.form = new FormGroup({});
- this.addField();
- }
-
- addField() {
- this.form.addControl(`host-${this.hosts.length}`, new FormControl('', [ validateHost ]));
- this.hosts.push('');
- }
-
- canMakeFriends() {
- return window.location.protocol === 'https:';
- }
-
- customTrackBy(index: number, obj: any): any {
- return index;
- }
-
- displayAddField(index: number) {
- return index === (this.hosts.length - 1);
- }
-
- displayRemoveField(index: number) {
- return (index !== 0 || this.hosts.length > 1) && index !== (this.hosts.length - 1);
- }
-
- isFormValid() {
- // Do not check the last input
- for (let i = 0; i < this.hosts.length - 1; i++) {
- if (!this.form.controls[`host-${i}`].valid) return false;
- }
-
- const lastIndex = this.hosts.length - 1;
- // If the last input (which is not the first) is empty, it's ok
- if (this.hosts[lastIndex] === '' && lastIndex !== 0) {
- return true;
- } else {
- return this.form.controls[`host-${lastIndex}`].valid;
- }
- }
-
- removeField(index: number) {
- // Remove the last control
- this.form.removeControl(`host-${this.hosts.length - 1}`);
- this.hosts.splice(index, 1);
- }
-
- makeFriends() {
- this.error = '';
-
- const notEmptyHosts = this.getNotEmptyHosts();
- if (notEmptyHosts.length === 0) {
- this.error = 'You need to specify at least 1 host.';
- return;
- }
-
- if (!this.isHostsUnique(notEmptyHosts)) {
- this.error = 'Hosts need to be unique.';
- return;
- }
-
- const confirmMessage = 'Are you sure to make friends with:\n - ' + notEmptyHosts.join('\n - ');
- if (!confirm(confirmMessage)) return;
-
- this.friendService.makeFriends(notEmptyHosts).subscribe(
- status => {
- alert('Make friends request sent!');
- this.router.navigate([ '/admin/friends/list' ]);
- },
- error => alert(error.text)
- );
- }
-
- private getNotEmptyHosts() {
- const notEmptyHosts = [];
-
- Object.keys(this.form.value).forEach((hostKey) => {
- const host = this.form.value[hostKey];
- if (host !== '') notEmptyHosts.push(host);
- });
-
- return notEmptyHosts;
- }
-
- private isHostsUnique(hosts: string[]) {
- return hosts.every(host => hosts.indexOf(host) === hosts.lastIndexOf(host));
- }
-}
+++ /dev/null
-export * from './friend-add.component';
+++ /dev/null
-<h3>Friends list</h3>
-
-<table class="table table-hover">
- <thead>
- <tr>
- <th class="table-column-id">ID</th>
- <th>Host</th>
- <th>Score</th>
- <th>Created Date</th>
- </tr>
- </thead>
-
- <tbody>
- <tr *ngFor="let friend of friends">
- <td>{{ friend.id }}</td>
- <td>{{ friend.host }}</td>
- <td>{{ friend.score }}</td>
- <td>{{ friend.createdAt | date: 'medium' }}</td>
- </tr>
- </tbody>
-</table>
-
-<a *ngIf="friends && friends.length !== 0" class="add-user btn btn-danger pull-left" (click)="quitFriends()">
- Quit friends
-</a>
-
-<a *ngIf="friends?.length === 0" class="add-user btn btn-success pull-right" [routerLink]="['/admin/friends/add']">
- Make friends
-</a>
+++ /dev/null
-table {
- margin-bottom: 40px;
-}
+++ /dev/null
-import { Component, OnInit } from '@angular/core';
-
-import { Friend, FriendService } from '../shared';
-
-@Component({
- selector: 'my-friend-list',
- templateUrl: './friend-list.component.html',
- styleUrls: [ './friend-list.component.scss' ]
-})
-export class FriendListComponent implements OnInit {
- friends: Friend[];
-
- constructor(private friendService: FriendService) { }
-
- ngOnInit() {
- this.getFriends();
- }
-
- quitFriends() {
- if (!confirm('Are you sure?')) return;
-
- this.friendService.quitFriends().subscribe(
- status => {
- alert('Quit friends!');
- this.getFriends();
- },
- error => alert(error.text)
- );
- }
-
- private getFriends() {
- this.friendService.getFriends().subscribe(
- res => this.friends = res.friends,
-
- err => alert(err.text)
- );
- }
-}
+++ /dev/null
-export * from './friend-list.component';
+++ /dev/null
-import { Component } from '@angular/core';
-
-@Component({
- template: '<router-outlet></router-outlet>'
-})
-
-export class FriendsComponent {
-}
+++ /dev/null
-import { Routes } from '@angular/router';
-
-import { FriendsComponent } from './friends.component';
-import { FriendAddComponent } from './friend-add';
-import { FriendListComponent } from './friend-list';
-
-export const FriendsRoutes: Routes = [
- {
- path: 'friends',
- component: FriendsComponent,
- children: [
- {
- path: '',
- redirectTo: 'list',
- pathMatch: 'full'
- },
- {
- path: 'list',
- component: FriendListComponent,
- data: {
- meta: {
- titleSuffix: ' - Friends list'
- }
- }
- },
- {
- path: 'add',
- component: FriendAddComponent,
- data: {
- meta: {
- titleSuffix: ' - Add friends'
- }
- }
- }
- ]
- }
-];
+++ /dev/null
-export * from './friend-add';
-export * from './friend-list';
-export * from './shared';
-export * from './friends.component';
-export * from './friends.routes';
+++ /dev/null
-export interface Friend {
- id: string;
- host: string;
- score: number;
- createdAt: Date;
-}
+++ /dev/null
-import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/operator/map';
-
-import { Friend } from './friend.model';
-import { AuthHttp, RestExtractor, ResultList } from '../../../shared';
-
-@Injectable()
-export class FriendService {
- private static BASE_FRIEND_URL: string = '/api/v1/pods/';
-
- constructor (
- private authHttp: AuthHttp,
- private restExtractor: RestExtractor
- ) {}
-
- getFriends() {
- return this.authHttp.get(FriendService.BASE_FRIEND_URL)
- .map(this.restExtractor.extractDataList)
- .map(this.extractFriends)
- .catch((res) => this.restExtractor.handleError(res));
- }
-
- makeFriends(notEmptyHosts) {
- const body = {
- hosts: notEmptyHosts
- };
-
- return this.authHttp.post(FriendService.BASE_FRIEND_URL + 'makefriends', body)
- .map(this.restExtractor.extractDataBool)
- .catch((res) => this.restExtractor.handleError(res));
- }
-
- quitFriends() {
- return this.authHttp.get(FriendService.BASE_FRIEND_URL + 'quitfriends')
- .map(res => res.status)
- .catch((res) => this.restExtractor.handleError(res));
- }
-
- private extractFriends(result: ResultList) {
- const friends: Friend[] = result.data;
- const totalFriends = result.total;
-
- return { friends, totalFriends };
- }
-}
+++ /dev/null
-export * from './friend.model';
-export * from './friend.service';
+++ /dev/null
-export * from './friends';
-export * from './requests';
-export * from './users';
-export * from './admin-routing.module';
-export * from './admin.module';
-export * from './admin.component';
-export * from './menu-admin.component';
+++ /dev/null
-<menu class="col-md-2 col-sm-3 col-xs-3">
-
- <div class="panel-block">
- <div id="panel-users" class="panel-button">
- <span class="hidden-xs glyphicon glyphicon-user"></span>
- <a [routerLink]="['/admin/users/list']">List users</a>
- </div>
-
- <div id="panel-friends" class="panel-button">
- <span class="hidden-xs glyphicon glyphicon-cloud"></span>
- <a [routerLink]="['/admin/friends/list']">List friends</a>
- </div>
-
- <div id="panel-request-stats" class="panel-button">
- <span class="hidden-xs glyphicon glyphicon-stats"></span>
- <a [routerLink]="['/admin/requests/stats']">Request stats</a>
- </div>
-
- <div id="panel-video-abuses" class="panel-button">
- <span class="hidden-xs glyphicon glyphicon-alert"></span>
- <a [routerLink]="['/admin/video-abuses/list']">Video abuses</a>
- </div>
- </div>
-
- <div class="panel-block">
- <div id="panel-quit-administration" class="panel-button">
- <span class="hidden-xs glyphicon glyphicon-cog"></span>
- <a [routerLink]="['/videos/list']">Quit admin.</a>
- </div>
- </div>
-</menu>
+++ /dev/null
-import { Component } from '@angular/core';
-
-@Component({
- selector: 'my-menu-admin',
- templateUrl: './menu-admin.component.html'
-})
-export class MenuAdminComponent { }
+++ /dev/null
-export * from './request-stats';
-export * from './shared';
-export * from './requests.component';
-export * from './requests.routes';
+++ /dev/null
-export * from './request-stats.component';
+++ /dev/null
-<h3>Requests stats</h3>
-
-<div *ngIf="stats !== null">
- <div class="requests-general">
- <div>
- <span class="label-description">Remaining requests:</span>
- {{ stats.totalRequests }}
- </div>
-
- <div>
- <span class="label-description">Interval seconds between requests:</span>
- {{ stats.secondsInterval }}
- </div>
-
- <div>
- <span class="label-description">Remaining time before the scheduled request:</span>
- {{ stats.remainingSeconds }}
- </div>
- </div>
-
- <div class="requests-limit">
- <div>
- <span class="label-description">Maximum number of different pods for a scheduled request:</span>
- {{ stats.requestsLimitPods }}
- </div>
-
- <div>
- <span class="label-description">Maximum number of requests per pod for a scheduled request:</span>
- {{ stats.requestsLimitPerPod }}
- </div>
- </div>
-
-</div>
+++ /dev/null
-.label-description {
- display: inline-block;
- font-weight: bold;
- color: black;
-}
-
-.requests-general {
- .label-description {
- width: 320px;
- }
-}
-
-.requests-limit {
- margin-top: 20px;
-
- .label-description {
- width: 430px;
- }
-}
+++ /dev/null
-import { setInterval } from 'timers'
-import { Component, OnInit, OnDestroy } from '@angular/core';
-
-import { RequestService, RequestStats } from '../shared';
-
-@Component({
- selector: 'my-request-stats',
- templateUrl: './request-stats.component.html',
- styleUrls: [ './request-stats.component.scss' ]
-})
-export class RequestStatsComponent implements OnInit, OnDestroy {
- stats: RequestStats = null;
-
- private interval: NodeJS.Timer = null;
-
- constructor(private requestService: RequestService) { }
-
- ngOnInit() {
- this.getStats();
- this.runInterval();
- }
-
- ngOnDestroy() {
- if (this.stats !== null && this.stats.secondsInterval !== null) {
- clearInterval(this.interval);
- }
- }
-
- getStats() {
- this.requestService.getStats().subscribe(
- stats => this.stats = stats,
-
- err => alert(err.text)
- );
- }
-
- private runInterval() {
- this.interval = setInterval(() => {
- this.stats.remainingMilliSeconds -= 1000;
-
- if (this.stats.remainingMilliSeconds <= 0) {
- setTimeout(() => this.getStats(), this.stats.remainingMilliSeconds + 100);
- }
- }, 1000);
- }
-
-
-}
+++ /dev/null
-import { Component } from '@angular/core';
-
-@Component({
- template: '<router-outlet></router-outlet>'
-})
-
-export class RequestsComponent {
-}
+++ /dev/null
-import { Routes } from '@angular/router';
-
-import { RequestsComponent } from './requests.component';
-import { RequestStatsComponent } from './request-stats';
-
-export const RequestsRoutes: Routes = [
- {
- path: 'requests',
- component: RequestsComponent,
- children: [
- {
- path: '',
- redirectTo: 'stats',
- pathMatch: 'full'
- },
- {
- path: 'stats',
- component: RequestStatsComponent,
- data: {
- meta: {
- titleSuffix: ' - Request stats'
- }
- }
- }
- ]
- }
-];
+++ /dev/null
-export * from './request-stats.model';
-export * from './request.service';
+++ /dev/null
-export interface Request {
- request: any;
- to: any;
-}
-
-export class RequestStats {
- requestsLimitPods: number;
- requestsLimitPerPod: number;
- milliSecondsInterval: number;
- remainingMilliSeconds: number;
- totalRequests: number;
-
- constructor(hash: {
- requestsLimitPods: number,
- requestsLimitPerPod: number,
- milliSecondsInterval: number,
- remainingMilliSeconds: number,
- totalRequests: number;
- }) {
- this.requestsLimitPods = hash.requestsLimitPods;
- this.requestsLimitPerPod = hash.requestsLimitPerPod;
- this.milliSecondsInterval = hash.milliSecondsInterval;
- this.remainingMilliSeconds = hash.remainingMilliSeconds;
- this.totalRequests = hash.totalRequests;
- }
-
- get remainingSeconds() {
- return Math.floor(this.remainingMilliSeconds / 1000);
- }
-
- get secondsInterval() {
- return Math.floor(this.milliSecondsInterval / 1000);
- }
-
-}
+++ /dev/null
-import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/operator/map';
-
-import { RequestStats } from './request-stats.model';
-import { AuthHttp, RestExtractor } from '../../../shared';
-
-@Injectable()
-export class RequestService {
- private static BASE_REQUEST_URL: string = '/api/v1/requests/';
-
- constructor (
- private authHttp: AuthHttp,
- private restExtractor: RestExtractor
- ) {}
-
- getStats(): Observable<RequestStats> {
- return this.authHttp.get(RequestService.BASE_REQUEST_URL + 'stats')
- .map(this.restExtractor.extractDataGet)
- .map((data) => new RequestStats(data))
- .catch((res) => this.restExtractor.handleError(res));
- }
-}
+++ /dev/null
-export * from './shared';
-export * from './user-add';
-export * from './user-list';
-export * from './users.component';
-export * from './users.routes';
+++ /dev/null
-export * from './user.service';
+++ /dev/null
-import { Injectable } from '@angular/core';
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/operator/map';
-
-import { AuthHttp, RestExtractor, ResultList, User } from '../../../shared';
-
-@Injectable()
-export class UserService {
- // TODO: merge this constant with account
- private static BASE_USERS_URL = '/api/v1/users/';
-
- constructor(
- private authHttp: AuthHttp,
- private restExtractor: RestExtractor
- ) {}
-
- addUser(username: string, password: string) {
- const body = {
- username,
- password
- };
-
- return this.authHttp.post(UserService.BASE_USERS_URL, body)
- .map(this.restExtractor.extractDataBool)
- .catch(this.restExtractor.handleError);
- }
-
- getUsers() {
- return this.authHttp.get(UserService.BASE_USERS_URL)
- .map(this.restExtractor.extractDataList)
- .map(this.extractUsers)
- .catch((res) => this.restExtractor.handleError(res));
- }
-
- removeUser(user: User) {
- return this.authHttp.delete(UserService.BASE_USERS_URL + user.id);
- }
-
- private extractUsers(result: ResultList) {
- const usersJson = result.data;
- const totalUsers = result.total;
- const users = [];
- for (const userJson of usersJson) {
- users.push(new User(userJson));
- }
-
- return { users, totalUsers };
- }
-}
+++ /dev/null
-export * from './user-add.component';
+++ /dev/null
-<h3>Add user</h3>
-
-<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
-
-<form role="form" (ngSubmit)="addUser()" [formGroup]="form">
- <div class="form-group">
- <label for="username">Username</label>
- <input
- type="text" class="form-control" id="username" placeholder="Username"
- formControlName="username"
- >
- <div *ngIf="formErrors.username" class="alert alert-danger">
- {{ formErrors.username }}
- </div>
- </div>
-
- <div class="form-group">
- <label for="password">Password</label>
- <input
- type="password" class="form-control" id="password" placeholder="Password"
- formControlName="password"
- >
- <div *ngIf="formErrors.password" class="alert alert-danger">
- {{ formErrors.password }}
- </div>
- </div>
-
- <input type="submit" value="Add user" class="btn btn-default" [disabled]="!form.valid">
-</form>
+++ /dev/null
-import { Component, OnInit } from '@angular/core';
-import { FormBuilder, FormGroup } from '@angular/forms';
-import { Router } from '@angular/router';
-
-import { UserService } from '../shared';
-import { FormReactive, USER_USERNAME, USER_PASSWORD } from '../../../shared';
-
-@Component({
- selector: 'my-user-add',
- templateUrl: './user-add.component.html'
-})
-export class UserAddComponent extends FormReactive implements OnInit {
- error: string = null;
-
- form: FormGroup;
- formErrors = {
- 'username': '',
- 'password': ''
- };
- validationMessages = {
- 'username': USER_USERNAME.MESSAGES,
- 'password': USER_PASSWORD.MESSAGES,
- };
-
- constructor(
- private formBuilder: FormBuilder,
- private router: Router,
- private userService: UserService
- ) {
- super();
- }
-
- buildForm() {
- this.form = this.formBuilder.group({
- username: [ '', USER_USERNAME.VALIDATORS ],
- password: [ '', USER_PASSWORD.VALIDATORS ],
- });
-
- this.form.valueChanges.subscribe(data => this.onValueChanged(data));
- }
-
- ngOnInit() {
- this.buildForm();
- }
-
- addUser() {
- this.error = null;
-
- const { username, password } = this.form.value;
-
- this.userService.addUser(username, password).subscribe(
- ok => this.router.navigate([ '/admin/users/list' ]),
-
- err => this.error = err.text
- );
- }
-}
+++ /dev/null
-export * from './user-list.component';
+++ /dev/null
-<h3>Users list</h3>
-
-<table class="table table-hover">
- <thead>
- <tr>
- <th class="table-column-id">ID</th>
- <th>Username</th>
- <th>Created Date</th>
- <th class="text-right">Remove</th>
- </tr>
- </thead>
-
- <tbody>
- <tr *ngFor="let user of users">
- <td>{{ user.id }}</td>
- <td>{{ user.username }}</td>
- <td>{{ user.createdAt | date: 'medium' }}</td>
- <td class="text-right">
- <span class="glyphicon glyphicon-remove" *ngIf="!user.isAdmin()" (click)="removeUser(user)"></span>
- </td>
- </tr>
- </tbody>
-</table>
-
-<a class="add-user btn btn-success pull-right" [routerLink]="['/admin/users/add']">
- <span class="glyphicon glyphicon-plus"></span>
- Add user
-</a>
+++ /dev/null
-.glyphicon-remove {
- cursor: pointer;
-}
-
-.add-user {
- margin-top: 10px;
-}
+++ /dev/null
-import { Component, OnInit } from '@angular/core';
-
-import { User } from '../../../shared';
-import { UserService } from '../shared';
-
-@Component({
- selector: 'my-user-list',
- templateUrl: './user-list.component.html',
- styleUrls: [ './user-list.component.scss' ]
-})
-export class UserListComponent implements OnInit {
- totalUsers: number;
- users: User[];
-
- constructor(private userService: UserService) {}
-
- ngOnInit() {
- this.getUsers();
- }
-
- getUsers() {
- this.userService.getUsers().subscribe(
- ({ users, totalUsers }) => {
- this.users = users;
- this.totalUsers = totalUsers;
- },
-
- err => alert(err.text)
- );
- }
-
-
- removeUser(user: User) {
- if (confirm('Are you sure?')) {
- this.userService.removeUser(user).subscribe(
- () => this.getUsers(),
-
- err => alert(err.text)
- );
- }
- }
-}
+++ /dev/null
-import { Component } from '@angular/core';
-
-@Component({
- template: '<router-outlet></router-outlet>'
-})
-
-export class UsersComponent {
-}
+++ /dev/null
-import { Routes } from '@angular/router';
-
-import { UsersComponent } from './users.component';
-import { UserAddComponent } from './user-add';
-import { UserListComponent } from './user-list';
-
-export const UsersRoutes: Routes = [
- {
- path: 'users',
- component: UsersComponent,
- children: [
- {
- path: '',
- redirectTo: 'list',
- pathMatch: 'full'
- },
- {
- path: 'list',
- component: UserListComponent,
- data: {
- meta: {
- titleSuffix: ' - Users list'
- }
- }
- },
- {
- path: 'add',
- component: UserAddComponent,
- data: {
- meta: {
- titleSuffix: ' - Add a user'
- }
- }
- }
- ]
- }
-];
+++ /dev/null
-export * from './video-abuse-list';
-export * from './video-abuses.component';
-export * from './video-abuses.routes';
+++ /dev/null
-export * from './video-abuse-list.component';
+++ /dev/null
-<h3>Video abuses list</h3>
-
-<table class="table table-hover">
- <thead>
- <tr>
- <th class="cell-id">ID</th>
- <th class="cell-reason">Reason</th>
- <th>Reporter pod host</th>
- <th>Reporter username</th>
- <th>Video</th>
- <th>Created at</th>
- </tr>
- </thead>
-
- <tbody>
- <tr *ngFor="let videoAbuse of videoAbuses">
- <td>{{ videoAbuse.id }}</td>
- <td>{{ videoAbuse.reason }}</td>
- <td>{{ videoAbuse.reporterPodHost }}</td>
- <td>{{ videoAbuse.reporterUsername }}</td>
- <td>
- <a [routerLink]="buildVideoLink(videoAbuse)" title="Go to video">{{ videoAbuse.videoId }}</a>
- </td>
- <td>{{ videoAbuse.createdAt | date: 'medium' }}</td>
- </tr>
- </tbody>
-</table>
+++ /dev/null
-.cell-id {
- width: 40px;
-}
-
-.cell-reason {
- width: 200px;
-}
+++ /dev/null
-import { setInterval } from 'timers'
-import { Component, OnInit } from '@angular/core';
-
-import { VideoAbuseService, VideoAbuse} from '../../../shared';
-
-@Component({
- selector: 'my-video-abuse-list',
- templateUrl: './video-abuse-list.component.html',
- styleUrls: [ './video-abuse-list.component.scss' ]
-})
-export class VideoAbuseListComponent implements OnInit {
- videoAbuses: VideoAbuse[];
-
- constructor(private videoAbuseService: VideoAbuseService) { }
-
- ngOnInit() {
- this.getVideoAbuses();
- }
-
- buildVideoLink(videoAbuse: VideoAbuse) {
- return `/videos/${videoAbuse.videoId}`;
- }
-
- private getVideoAbuses() {
- this.videoAbuseService.getVideoAbuses().subscribe(
- res => this.videoAbuses = res.videoAbuses,
-
- err => alert(err.text)
- );
- }
-}
+++ /dev/null
-import { Component } from '@angular/core';
-
-@Component({
- template: '<router-outlet></router-outlet>'
-})
-
-export class VideoAbusesComponent {
-}
+++ /dev/null
-import { Routes } from '@angular/router';
-
-import { VideoAbusesComponent } from './video-abuses.component';
-import { VideoAbuseListComponent } from './video-abuse-list';
-
-export const VideoAbusesRoutes: Routes = [
- {
- path: 'video-abuses',
- component: VideoAbusesComponent
- ,
- children: [
- {
- path: '',
- redirectTo: 'list',
- pathMatch: 'full'
- },
- {
- path: 'list',
- component: VideoAbuseListComponent,
- data: {
- meta: {
- titleSuffix: ' - Video abuses list'
- }
- }
- }
- ]
- }
-];
path: '',
redirectTo: '/videos/list',
pathMatch: 'full'
+ },
+ {
+ path: 'admin',
+ loadChildren: './+admin#AdminModule'
}
];
import { AppState } from './app.service';
import { AccountModule } from './account';
-import { AdminModule } from './admin';
import { CoreModule } from './core';
import { LoginModule } from './login';
import { SharedModule } from './shared';
MetaModule.forRoot(metaConfig),
AccountModule,
- AdminModule,
CoreModule,
LoginModule,
SharedModule,
import { RouterModule } from '@angular/router';
import { AuthService } from './auth';
-import { MenuComponent } from './menu';
+import { MenuComponent, MenuAdminComponent } from './menu';
import { throwIfAlreadyLoaded } from './module-import-guard';
@NgModule({
HttpModule,
RouterModule
],
- declarations: [ MenuComponent ],
- exports: [ MenuComponent ],
+ declarations: [
+ MenuComponent,
+ MenuAdminComponent
+ ],
+ exports: [
+ MenuComponent,
+ MenuAdminComponent
+ ],
providers: [ AuthService ]
})
export class CoreModule {
export * from './menu.component';
+export * from './menu-admin.component';
--- /dev/null
+<menu class="col-md-2 col-sm-3 col-xs-3">
+
+ <div class="panel-block">
+ <div id="panel-users" class="panel-button">
+ <span class="hidden-xs glyphicon glyphicon-user"></span>
+ <a [routerLink]="['/admin/users/list']">List users</a>
+ </div>
+
+ <div id="panel-friends" class="panel-button">
+ <span class="hidden-xs glyphicon glyphicon-cloud"></span>
+ <a [routerLink]="['/admin/friends/list']">List friends</a>
+ </div>
+
+ <div id="panel-request-stats" class="panel-button">
+ <span class="hidden-xs glyphicon glyphicon-stats"></span>
+ <a [routerLink]="['/admin/requests/stats']">Request stats</a>
+ </div>
+
+ <div id="panel-video-abuses" class="panel-button">
+ <span class="hidden-xs glyphicon glyphicon-alert"></span>
+ <a [routerLink]="['/admin/video-abuses/list']">Video abuses</a>
+ </div>
+ </div>
+
+ <div class="panel-block">
+ <div id="panel-quit-administration" class="panel-button">
+ <span class="hidden-xs glyphicon glyphicon-cog"></span>
+ <a [routerLink]="['/videos/list']">Quit admin.</a>
+ </div>
+ </div>
+</menu>
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-menu-admin',
+ templateUrl: './menu-admin.component.html'
+})
+export class MenuAdminComponent { }