Added Login, TTS Login, Policies
This commit is contained in:
parent
0c7fbf1cb9
commit
65f4172bc2
2
.gitignore
vendored
2
.gitignore
vendored
@ -40,3 +40,5 @@ testem.log
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
src/environments/*
|
@ -1,15 +1,13 @@
|
||||
import { CommonModule, DatePipe, isPlatformBrowser } from '@angular/common';
|
||||
import { Component, OnInit, Inject, PLATFORM_ID, NgZone, OnDestroy } from '@angular/core';
|
||||
import { Router, RouterModule, RouterOutlet, Routes } from '@angular/router';
|
||||
import { Router, RouterOutlet } from '@angular/router';
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { HermesClientService } from './hermes-client.service';
|
||||
import { AuthGuard } from './shared/auth/auth.guard'
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Policy, PolicyScope } from './shared/models/policy';
|
||||
import { PolicyComponent } from "./policy/policy.component";
|
||||
import { NavigationComponent } from "./navigation/navigation.component";
|
||||
import EventService from './shared/services/EventService';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ApiAuthenticationService } from './shared/services/api/api-authentication.service';
|
||||
|
||||
@Component({
|
||||
@ -23,13 +21,14 @@ import { ApiAuthenticationService } from './shared/services/api/api-authenticati
|
||||
export class AppComponent implements OnInit, OnDestroy {
|
||||
private isBrowser: boolean;
|
||||
private ngZone: NgZone;
|
||||
private subscription: Subscription | undefined;
|
||||
private subscriptions: Subscription[];
|
||||
pipe = new DatePipe('en-US')
|
||||
|
||||
|
||||
constructor(private auth: ApiAuthenticationService, private client: HermesClientService, private events: EventService, private http: HttpClient, ngZone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) {
|
||||
constructor(private auth: ApiAuthenticationService, private client: HermesClientService, private events: EventService, private router: Router, ngZone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) {
|
||||
this.ngZone = ngZone;
|
||||
this.isBrowser = isPlatformBrowser(this.platformId)
|
||||
this.isBrowser = isPlatformBrowser(this.platformId);
|
||||
this.subscriptions = [];
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -38,13 +37,30 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.auth.update();
|
||||
|
||||
const rand = Math.random() * 100000 | 0;
|
||||
this.client.subscribe(4, (data) => console.log("Request ack received", rand, data));
|
||||
|
||||
this.addSubscription(this.events.listen('logoff', (message) => {
|
||||
localStorage.removeItem('jwt');
|
||||
if (!document.location.href.includes('/login')) {
|
||||
this.router.navigate(['/login?warning=' + message]);
|
||||
}
|
||||
}));
|
||||
|
||||
this.addSubscription(this.events.listen('login', (_) => {
|
||||
if (document.location.href.includes('/login')) {
|
||||
this.router.navigate(['/tts-login']);
|
||||
}
|
||||
}));
|
||||
|
||||
this.client.connect();
|
||||
this.ngZone.runOutsideAngular(() => setInterval(() => this.client.heartbeat(), 15000));
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
for (let s of this.subscriptions) {
|
||||
s.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private addSubscription(s: Subscription) {
|
||||
this.subscriptions.push(s);
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { HermesSocketService } from './hermes-socket.service';
|
||||
import EventService from './shared/services/EventService';
|
||||
|
||||
@ -39,6 +38,15 @@ export class HermesClientService {
|
||||
return this.listen();
|
||||
}
|
||||
|
||||
public disconnect() {
|
||||
if (!this.connected)
|
||||
return;
|
||||
|
||||
this.socket.close();
|
||||
this.connected = false;
|
||||
this.events.emit('tts_logoff', null);
|
||||
}
|
||||
|
||||
private send(op: number, data: any) {
|
||||
if (op != 0)
|
||||
console.log("TX:", data);
|
||||
@ -61,6 +69,54 @@ export class HermesClientService {
|
||||
});
|
||||
}
|
||||
|
||||
public createPolicy(groupId: string, path: string, usage: number, timespan: number) {
|
||||
if (!this.logged_in)
|
||||
return;
|
||||
|
||||
this.send(3, {
|
||||
request_id: null,
|
||||
type: "create_policy",
|
||||
data: {
|
||||
groupId, path, count: usage, span: timespan
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public deletePolicy(id: string) {
|
||||
if (!this.logged_in)
|
||||
return;
|
||||
|
||||
this.send(3, {
|
||||
request_id: null,
|
||||
type: "delete_policy",
|
||||
data: {
|
||||
id
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public fetchPolicies() {
|
||||
if (!this.logged_in)
|
||||
return;
|
||||
|
||||
this.send(3, {
|
||||
request_id: null,
|
||||
type: "get_policies",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
|
||||
public fetchPermissionsAndGroups() {
|
||||
if (!this.logged_in)
|
||||
return;
|
||||
|
||||
this.send(3, {
|
||||
request_id: null,
|
||||
type: "get_permissions",
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
|
||||
public heartbeat() {
|
||||
const date = new Date()
|
||||
this.send(0, {
|
||||
@ -75,6 +131,19 @@ export class HermesClientService {
|
||||
this.subscriptions[code].push(action);
|
||||
}
|
||||
|
||||
public updatePolicy(id: string, groupId: string, path: string, usage: number, timespan: number) {
|
||||
if (!this.logged_in)
|
||||
return;
|
||||
|
||||
this.send(3, {
|
||||
request_id: null,
|
||||
type: "update_policy",
|
||||
data: {
|
||||
id, groupId, path, count: usage, span: timespan
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private listen() {
|
||||
return this.socket.subscribe({
|
||||
next: (message: any) => {
|
||||
|
@ -25,7 +25,7 @@ export class HermesSocketService implements OnInit {
|
||||
|
||||
private getNewWebSocket() {
|
||||
return webSocket({
|
||||
url: WS_ENDPOINT
|
||||
url: environment.WSS_ENDPOINT
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { Policy } from '../shared/models/policy';
|
||||
import EventService from '../shared/services/EventService';
|
||||
import { map, Observable, startWith } from 'rxjs';
|
||||
import { HermesClientService } from '../hermes-client.service';
|
||||
|
||||
const Policies = [
|
||||
{ path: "tts", description: "Anything to do with TTS" },
|
||||
@ -48,7 +49,7 @@ export class PolicyAddFormComponent {
|
||||
newPolicyName: string = '';
|
||||
filteredPolicies: Observable<string[]>;
|
||||
|
||||
constructor(private events: EventService) {
|
||||
constructor(private events: EventService, private hermes: HermesClientService) {
|
||||
this.filteredPolicies = this.myControl.valueChanges.pipe(
|
||||
startWith(''),
|
||||
map(value => this._filter(value || '')),
|
||||
@ -69,7 +70,7 @@ export class PolicyAddFormComponent {
|
||||
}
|
||||
|
||||
addNewPolicy() {
|
||||
console.log('new policy name given', this.newPolicyName)
|
||||
this.events.emit('addPolicy', this.newPolicyName)
|
||||
this.events.emit('addPolicy', this.newPolicyName);
|
||||
this.newPolicyName = "";
|
||||
}
|
||||
}
|
||||
|
@ -6,26 +6,47 @@
|
||||
<!-- Position Column -->
|
||||
<ng-container matColumnDef="path">
|
||||
<th mat-header-cell *matHeaderCellDef>Path</th>
|
||||
<td mat-cell *matCellDef="let policy">
|
||||
{{policy.path}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="group">
|
||||
<th mat-header-cell *matHeaderCellDef>Group</th>
|
||||
<td mat-cell *matCellDef="let policy">
|
||||
@if (policy.editing) {
|
||||
<input type="text" [(ngModel)]="policy.path" />
|
||||
<input type="text" [(ngModel)]="policy.temp_group_name" />
|
||||
}
|
||||
@if (!policy.editing) {
|
||||
{{policy.path}}
|
||||
{{groups[policy.group_id].name}}
|
||||
}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="usage">
|
||||
<th mat-header-cell *matHeaderCellDef> Usage </th>
|
||||
<td mat-cell *matCellDef="let policy"> {{policy.name}} </td>
|
||||
<th mat-header-cell *matHeaderCellDef>Usage per span</th>
|
||||
<td mat-cell *matCellDef="let policy">
|
||||
@if (policy.editing) {
|
||||
<input type="number" [(ngModel)]="policy.usage" (keypress)="($event.charCode >= 48 && $event.charCode < 58)" />
|
||||
}
|
||||
@if (!policy.editing) {
|
||||
{{policy.usage}}
|
||||
}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Weight Column -->
|
||||
<ng-container matColumnDef="span">
|
||||
<th mat-header-cell *matHeaderCellDef> Span </th>
|
||||
<td mat-cell *matCellDef="let policy"> {{policy.weight}} </td>
|
||||
<th mat-header-cell *matHeaderCellDef>Span (ms)</th>
|
||||
<td mat-cell *matCellDef="let policy">
|
||||
@if (policy.editing) {
|
||||
<input type="number" [(ngModel)]="policy.span" (keypress)="($event.charCode >= 48 && $event.charCode < 58)" />
|
||||
}
|
||||
@if (!policy.editing) {
|
||||
{{policy.span}}
|
||||
}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Symbol Column -->
|
||||
|
@ -5,6 +5,7 @@ import EventService from '../shared/services/EventService';
|
||||
import { Policy } from '../shared/models/policy';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HermesClientService } from '../hermes-client.service';
|
||||
|
||||
@Component({
|
||||
selector: 'policy-table',
|
||||
@ -15,23 +16,78 @@ import { FormsModule } from '@angular/forms';
|
||||
})
|
||||
export class PolicyTableComponent implements OnInit, OnDestroy {
|
||||
@Input() policies: Policy[] = []
|
||||
displayedColumns = ['path', 'usage', 'span', 'actions']
|
||||
displayedColumns = ['path', 'group', 'usage', 'span', 'actions']
|
||||
groups: { [id: string]: { id: string, name: string, priority: number } }
|
||||
|
||||
@ViewChild(MatTable) table: MatTable<Policy>;
|
||||
|
||||
private subscription: Subscription | undefined;
|
||||
|
||||
constructor(private events: EventService) {
|
||||
constructor(private events: EventService, private hermes: HermesClientService) {
|
||||
this.table = {} as MatTable<Policy>;
|
||||
this.groups = {};
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.subscription = this.events.listen('addPolicy', (payload) => {
|
||||
console.log('adding policy', payload);
|
||||
this.policies.push(new Policy(payload, 1, 5000, true, true));
|
||||
console.log(this.policies);
|
||||
if (!payload)
|
||||
return;
|
||||
if (this.policies.map(p => p.path).includes(payload)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.policies.push(new Policy("", "", payload, 1, 5000, "", true, true));
|
||||
this.table.renderRows();
|
||||
});
|
||||
this.hermes.subscribe(4, (response: any) => {
|
||||
console.log('request received: ', response);
|
||||
if (response.request.type == "get_policies") {
|
||||
for (let policy of response.data) {
|
||||
this.policies.push(new Policy(policy.id, policy.group_id, policy.path, policy.usage, policy.span, "", false, false));
|
||||
}
|
||||
this.table.renderRows();
|
||||
} else if (response.request.type == "create_policy") {
|
||||
console.log("create policy", response);
|
||||
const policy = this.policies.find(p => this.groups[response.data.group_id].name == p.temp_group_name && p.path == response.data.path);
|
||||
if (policy == null) {
|
||||
this.policies.push(new Policy(response.data.id, response.data.group_id, response.data.path, response.data.usage, response.data.span));
|
||||
} else {
|
||||
policy.id = response.data.id;
|
||||
policy.group_id = response.data.group_id;
|
||||
policy.editing = false;
|
||||
policy.isNew = false;
|
||||
}
|
||||
this.table.renderRows();
|
||||
} else if (response.request.type == "update_policy") {
|
||||
console.log("update policy", response);
|
||||
const policy = this.policies.find(p => p.id == response.data.id);
|
||||
if (policy == null) {
|
||||
this.policies.push(new Policy(response.data.id, response.data.group_id, response.data.path, response.data.usage, response.data.span));
|
||||
} else {
|
||||
policy.id = response.data.id;
|
||||
policy.group_id = response.data.group_id;
|
||||
policy.editing = false;
|
||||
policy.isNew = false;
|
||||
}
|
||||
this.table.renderRows();
|
||||
} else if (response.request.type == "delete_policy") {
|
||||
console.log('delete policy', response.request.data.id);
|
||||
const policy = this.policies.find(p => p.id == response.request.data.id);
|
||||
if (!policy) {
|
||||
console.log('Could not find the policy by id. Already deleted.');
|
||||
return;
|
||||
}
|
||||
const index = this.policies.indexOf(policy);
|
||||
if (index >= 0) {
|
||||
this.policies.splice(index, 1);
|
||||
this.table.renderRows();
|
||||
}
|
||||
} else if (response.request.type == "get_permissions") {
|
||||
this.groups = Object.assign({}, ...response.data.groups.map((g: any) => ({ [g.id]: g })));
|
||||
console.log(this.groups);
|
||||
}
|
||||
});
|
||||
this.hermes.fetchPolicies();
|
||||
this.hermes.fetchPermissionsAndGroups();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@ -40,27 +96,83 @@ export class PolicyTableComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
cancel(policy: Policy) {
|
||||
if (!policy.editing)
|
||||
return;
|
||||
|
||||
policy.path = policy.old_path ?? '';
|
||||
policy.usage = policy.old_usage ?? 1;
|
||||
policy.span = policy.old_span ?? 5000;
|
||||
policy.old_path = undefined;
|
||||
policy.old_span = undefined;
|
||||
policy.old_usage = undefined;
|
||||
policy.editing = false;
|
||||
this.table.renderRows();
|
||||
}
|
||||
|
||||
delete(policy: Policy) {
|
||||
const index = this.policies.indexOf(policy);
|
||||
if (index >= 0) {
|
||||
this.policies.splice(index, 1);
|
||||
this.table.renderRows();
|
||||
}
|
||||
this.hermes.deletePolicy(policy.id);
|
||||
}
|
||||
|
||||
edit(policy: Policy) {
|
||||
console.log('prior', policy.editing)
|
||||
policy.old_path = policy.path;
|
||||
policy.old_span = policy.span;
|
||||
policy.old_usage = policy.usage;
|
||||
policy.temp_group_name = this.groups[policy.group_id].name
|
||||
policy.editing = true;
|
||||
|
||||
}
|
||||
|
||||
save(policy: Policy) {
|
||||
policy.editing = false;
|
||||
policy.isNew = false;
|
||||
this.table.renderRows();
|
||||
if (!policy.temp_group_name) {
|
||||
console.log('group must be valid.');
|
||||
return;
|
||||
}
|
||||
const group = Object.values(this.groups).find(g => g.name);
|
||||
if (group == null) {
|
||||
console.log('group does not exist.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(policy.usage)) {
|
||||
console.log('usage must be a whole number.');
|
||||
return;
|
||||
}
|
||||
if (policy.usage < 1 || policy.usage > 99) {
|
||||
console.error('usage must be between 1 and 99.');
|
||||
return;
|
||||
}
|
||||
if (policy.usage % 1.0 != 0) {
|
||||
console.error('usage must be a whole number.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(policy.span)) {
|
||||
console.log('span must be a whole number.');
|
||||
return;
|
||||
}
|
||||
if (policy.span < 1000 || policy.span > 1800000) {
|
||||
console.error('span must be between 1 and 1800000.');
|
||||
return;
|
||||
}
|
||||
if (policy.span % 1.0 != 0) {
|
||||
console.error('span must be a whole number.');
|
||||
return;
|
||||
}
|
||||
|
||||
let group_id = policy?.group_id;
|
||||
for (let groupId in this.groups) {
|
||||
if (this.groups[groupId].name == policy?.temp_group_name) {
|
||||
group_id = groupId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (policy?.temp_group_name != this.groups[group_id].name) {
|
||||
console.log('no group found.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (policy.isNew) {
|
||||
this.hermes.createPolicy(group.id, policy.path, policy.usage, policy.span);
|
||||
} else {
|
||||
this.hermes.updatePolicy(policy.id, group.id, policy.path, policy.usage, policy.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,11 @@ export enum PolicyScope {
|
||||
}
|
||||
|
||||
export class Policy {
|
||||
constructor(public path: string, public usage: number, public span: number, public editing: boolean = false, public isNew: boolean = false) {
|
||||
public old_path: string|undefined;
|
||||
public old_usage: number|undefined;
|
||||
public old_span: number|undefined;
|
||||
|
||||
constructor(public id: string, public group_id: string, public path: string, public usage: number, public span: number, public temp_group_name: string = "", public editing: boolean = false, public isNew: boolean = false) {
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import EventService from '../EventService';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -8,7 +9,7 @@ export class ApiAuthenticationService {
|
||||
private authenticated: boolean;
|
||||
private lastCheck: Date;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
constructor(private http: HttpClient, private events: EventService) {
|
||||
this.authenticated = false;
|
||||
this.lastCheck = new Date();
|
||||
}
|
||||
@ -36,7 +37,16 @@ export class ApiAuthenticationService {
|
||||
}
|
||||
|
||||
private updateAuthenticated(value: boolean) {
|
||||
const previous = this.authenticated;
|
||||
this.authenticated = value;
|
||||
this.lastCheck = new Date();
|
||||
|
||||
if (previous != value) {
|
||||
if (value) {
|
||||
this.events.emit('login', null);
|
||||
} else {
|
||||
this.events.emit('logoff', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ export class TtsLoginComponent implements OnInit, OnDestroy {
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + localStorage.getItem('jwt')
|
||||
}
|
||||
}).subscribe((data: any) => this.api_keys = data.map((d: any) => d.id))
|
||||
}).subscribe((data: any) => this.api_keys = data.map((d: any) => d.id));
|
||||
|
||||
this.subscription = this.events.listen('tts_login_ack', _ => {
|
||||
if (document.location.href.includes('/tts-login')) {
|
||||
|
Loading…
Reference in New Issue
Block a user