update partey timeslots + minetest
This commit is contained in:
parent
72178dd7c4
commit
a11c74b91b
@ -19,10 +19,12 @@ import {UnavailableComponent} from './pages/unavailable/unavailable.component';
|
||||
import {NotfoundComponent} from './pages/notfound/notfound.component';
|
||||
import {UserComponent} from './pages/user/user.component'
|
||||
import {JitsiComponent} from './pages/jitsi/jitsi.component'
|
||||
import {ParteyTimeslotsComponent} from './pages/partey/timeslots/timeslots.compontent'
|
||||
import {AliasesComponent} from './pages/account/aliases/aliases.component';
|
||||
import {DomainsComponent} from './pages/account/domains/domains.component';
|
||||
import {InvitesComponent} from './pages/invites/invites.component';
|
||||
import {UrlShortenerComponent, UrlShortenerPasswordComponent} from './pages/urlshortener/urlshortener.component';
|
||||
import {MinetestAccountsComponent} from './pages/minetest/accounts/accounts.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', redirectTo: "/services", pathMatch: 'full'},
|
||||
@ -50,6 +52,8 @@ const routes: Routes = [
|
||||
{path: 'register', component: RegisterComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'tokens', component: TokensComponent, canActivate: [AuthGuard]},
|
||||
{path: 'jitsi', component: JitsiComponent, canActivate: [AuthenticatedGuard]},
|
||||
{path: 'partey/timeslots', component: ParteyTimeslotsComponent, canActivate: [AuthenticatedGuard]},
|
||||
{path: 'minetest/accounts', component: MinetestAccountsComponent, canActivate: [AuthenticatedGuard]},
|
||||
{path: 'urlshortener', component: UrlShortenerComponent, canActivate: [AuthenticatedGuard]},
|
||||
{path: 'urlshortener/:code', component: UrlShortenerPasswordComponent, canActivate: [AuthUpdateGuard]},
|
||||
{path: 'invites/:quota', component: InvitesComponent, canActivate: [AuthenticatedGuard]},
|
||||
|
@ -7,10 +7,10 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {HttpClientModule, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS} from '@angular/common/http';
|
||||
import {MaterialModule} from './material/material.module';
|
||||
import {QRCodeModule} from 'angularx-qrcode';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import {DatePipe} from '@angular/common';
|
||||
|
||||
|
||||
import { AutofocusDirective} from './material/autofocus';
|
||||
import {AutofocusDirective} from './material/autofocus';
|
||||
|
||||
import {I18nPipe} from './utils/i18n.pipe';
|
||||
import {ImprintComponent, PrivacyPolicyComponent, TermsOfServiceComponent} from './pages/general/general.component';
|
||||
@ -43,10 +43,12 @@ import {HtmlComponent} from './utils/html/html.component';
|
||||
import {ConfirmDialog} from './ui/confirm/confirm.component'
|
||||
import {UserComponent} from './pages/user/user.component'
|
||||
import {JitsiComponent, JitsiShareDialog} from './pages/jitsi/jitsi.component'
|
||||
import {ParteyTimeslotsComponent, ParteyTimeslotDialog} from './pages/partey/timeslots/timeslots.compontent'
|
||||
import {UrlShortenerComponent, UrlShortenerPasswordComponent, UrlShortenerShareDialog} from './pages/urlshortener/urlshortener.component'
|
||||
|
||||
|
||||
import {I18nService} from './services/i18n.service';
|
||||
import {MinetestAccountsComponent} from './pages/minetest/accounts/accounts.component';
|
||||
|
||||
|
||||
export function init_app(i18n: I18nService) {
|
||||
@ -99,6 +101,8 @@ export class XhrInterceptor implements HttpInterceptor {
|
||||
ConfirmDialog,
|
||||
UserComponent,
|
||||
JitsiComponent, JitsiShareDialog,
|
||||
ParteyTimeslotsComponent, ParteyTimeslotDialog,
|
||||
MinetestAccountsComponent,
|
||||
UrlShortenerComponent, UrlShortenerShareDialog, UrlShortenerPasswordComponent
|
||||
],
|
||||
imports: [
|
||||
|
43
src/app/pages/minetest/accounts/accounts.component.html
Normal file
43
src/app/pages/minetest/accounts/accounts.component.html
Normal file
@ -0,0 +1,43 @@
|
||||
<h3>{{'minetest.accounts' | i18n}}</h3>
|
||||
|
||||
|
||||
<table mat-table [dataSource]="minetestAccounts">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'minetest.accounts.name' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let minetestAccount">
|
||||
{{minetestAccount.name}}
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="minetestAccountsColumns"></tr>
|
||||
<tr mat-row *matRowDef="let myRowData; columns: minetestAccountsColumns"></tr>
|
||||
</table>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="create()" #formDirective="ngForm">
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<p>{{'minetest.accounts.info' | i18n}}</p>
|
||||
<p *ngIf="!minetestAccountsQuota">{{'minetest.accounts.noQuota' | i18n}}</p>
|
||||
<div *ngIf="minetestAccountsQuota">
|
||||
<p>{{'minetest.accounts.left' | i18n:minetestAccountsQuota}}</p>
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'minetest.accounts.name' | i18n}}" formControlName="name"
|
||||
[(ngModel)]="minetestAccount.name" required pattern="[-_a-zA-Z0-9]+">
|
||||
<mat-error>
|
||||
{{'minetest.accounts.error.name' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-card class="warn">
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>{{'minetest.accounts.deletion' | i18n}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
</mat-card>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button *ngIf="minetestAccountsQuota && !working" mat-raised-button color="primary" [disabled]="form.invalid">
|
||||
{{'minetest.accounts.create' | i18n}}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
</form>
|
30
src/app/pages/minetest/accounts/accounts.component.scss
Normal file
30
src/app/pages/minetest/accounts/accounts.component.scss
Normal file
@ -0,0 +1,30 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mat-header-cell,
|
||||
.mat-cell {
|
||||
&.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-cell .mat-button {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.align-right{
|
||||
display: flex;
|
||||
padding: 21px 0;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.url {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
77
src/app/pages/minetest/accounts/accounts.component.ts
Normal file
77
src/app/pages/minetest/accounts/accounts.component.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import {Component, OnInit, ViewChild} from '@angular/core';
|
||||
import {FormBuilder, FormGroup, Validators, NgForm} from '@angular/forms';
|
||||
|
||||
import {QuotaService} from '../../../services/quota.service';
|
||||
import {MinetestAccountsService} from '../../../services/minetest.accounts.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-minetest-accounts',
|
||||
templateUrl: './accounts.component.html',
|
||||
styleUrls: ['./accounts.component.scss']
|
||||
})
|
||||
export class MinetestAccountsComponent implements OnInit {
|
||||
|
||||
form: FormGroup;
|
||||
@ViewChild('formDirective') private formDirective: NgForm;
|
||||
minetestAccountsQuota: number = 0;
|
||||
minetestAccounts: any;
|
||||
minetestAccount: any = {};
|
||||
success: boolean;
|
||||
working: boolean;
|
||||
|
||||
minetestAccountsColumns = ["name"];
|
||||
|
||||
constructor(
|
||||
private quotaService: QuotaService,
|
||||
private formBuilder: FormBuilder,
|
||||
private minetestAccountsService: MinetestAccountsService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
name: ['', Validators.required],
|
||||
});
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
create(): void {
|
||||
this.working = true;
|
||||
|
||||
this.minetestAccountsService.create(this.minetestAccount).subscribe(response => {
|
||||
this.update();
|
||||
this.formDirective.resetForm();
|
||||
this.minetestAccount = {};
|
||||
this.working = false;
|
||||
}, (error) => {
|
||||
this.working = false;
|
||||
if(error.status == 409) {
|
||||
let errors = {};
|
||||
for(let code of error.error) {
|
||||
errors[code.field] = errors[code.field] || {};
|
||||
errors[code.field][code.code] = true;
|
||||
}
|
||||
|
||||
for(let code in errors) {
|
||||
this.form.get(code).setErrors(errors[code]);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
update() {
|
||||
this.minetestAccountsQuota = 0;
|
||||
this.quotaService.quotas().subscribe((data: any) => {
|
||||
for(let quota of data) {
|
||||
if(quota.name == "minetest_accounts") {
|
||||
this.minetestAccountsQuota = quota.value;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.minetestAccountsService.get().subscribe((data: any) => {
|
||||
this.minetestAccounts = data;
|
||||
})
|
||||
}
|
||||
|
||||
}
|
48
src/app/pages/partey/timeslots/timeslot.dialog.html
Normal file
48
src/app/pages/partey/timeslots/timeslot.dialog.html
Normal file
@ -0,0 +1,48 @@
|
||||
<h1 mat-dialog-title>
|
||||
<mat-icon inline="true">{{'partey.timeslots.type.' + timeslot.type + '.icon' | i18n}}</mat-icon> {{(timeslot.id ? 'partey.timeslots.edit' : 'partey.timeslots.create.' +
|
||||
timeslot.type) | i18n}}
|
||||
</h1>
|
||||
<mat-dialog-content>
|
||||
<h3 *ngIf="timeslot.id">{{'partey.timeslots.type.' + timeslot.type | i18n}}</h3>
|
||||
<form [formGroup]="form">
|
||||
<mat-form-field *ngIf="timeslot.type == 'VIDEO'">
|
||||
<input matInput [(ngModel)]="timeslot.stream" formControlName="stream"
|
||||
placeholder="{{'partey.timeslots.stream' | i18n}}">
|
||||
</mat-form-field>
|
||||
<mat-form-field *ngIf="timeslot.type == 'AUDIO' && timeslot.secret">
|
||||
<textarea [mat-autosize] matInput [value]="timeslot.secret" readonly placeholder="{{'partey.timeslots.secret' | i18n}}"></textarea>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput [ngxMatDatetimePicker]="startsPicker" [(ngModel)]="timeslot.starts" formControlName="starts"
|
||||
placeholder="{{'partey.timeslots.starts' | i18n}}">
|
||||
<mat-datepicker-toggle matSuffix [for]="startsPicker"></mat-datepicker-toggle>
|
||||
<ngx-mat-datetime-picker #startsPicker></ngx-mat-datetime-picker>
|
||||
<mat-error>
|
||||
{{'partey.timeslots.error.starts' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput [ngxMatDatetimePicker]="endsPicker" [(ngModel)]="timeslot.ends" formControlName="ends"
|
||||
placeholder="{{'partey.timeslots.ends' | i18n}}">
|
||||
<mat-datepicker-toggle matSuffix [for]="endsPicker"></mat-datepicker-toggle>
|
||||
<ngx-mat-datetime-picker #endsPicker></ngx-mat-datetime-picker>
|
||||
<mat-error>
|
||||
{{'partey.timeslots.error.ends' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput [(ngModel)]="timeslot.title" formControlName="title"
|
||||
placeholder="{{'partey.timeslots.title' | i18n}}">
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<textarea matInput [(ngModel)]="timeslot.description" formControlName="description"
|
||||
placeholder="{{'partey.timeslots.description' | i18n}}"></textarea>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
|
||||
<button [disabled]="form.invalid" mat-raised-button (click)="timeslot.id ? save(timeslot) : create(timeslot)"
|
||||
color="accent">{{ (timeslot.id ? 'partey.timeslots.save' : 'partey.timeslots.create') |
|
||||
i18n}}</button>
|
||||
</mat-dialog-actions>
|
7
src/app/pages/partey/timeslots/timeslot.dialog.scss
Normal file
7
src/app/pages/partey/timeslots/timeslot.dialog.scss
Normal file
@ -0,0 +1,7 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
mat-slide-toggle {
|
||||
margin-bottom: 24px;
|
||||
}
|
117
src/app/pages/partey/timeslots/timeslots.component.html
Normal file
117
src/app/pages/partey/timeslots/timeslots.component.html
Normal file
@ -0,0 +1,117 @@
|
||||
<h3>{{'partey.timeslots' | i18n}}</h3>
|
||||
|
||||
<div *ngIf="timeslots">
|
||||
<mat-form-field>
|
||||
<input matInput [formControl]="searchFormControl" placeholder="{{'partey.timeslots.filter.search' | i18n}}">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{'partey.timeslots.filter.owner' | i18n}}</mat-label>
|
||||
<mat-select [formControl]="ownerFormControl">
|
||||
<mat-option value="">{{'partey.timeslots.filter.owner.mine' | i18n}}</mat-option>
|
||||
<mat-option value="others">{{'partey.timeslots.filter.owner.others' | i18n}} </mat-option>
|
||||
<mat-option value="all">{{'partey.timeslots.filter.owner.all' | i18n}} </mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>{{'partey.timeslots.filter.type' | i18n}}</mat-label>
|
||||
<mat-select [formControl]="typeFormControl">
|
||||
<mat-option value="">{{'partey.timeslots.filter.type.all' | i18n}}</mat-option>
|
||||
<mat-option *ngFor="let type of types" [value]="type">
|
||||
<mat-icon inline="true">{{'partey.timeslots.type.' + type + '.icon' | i18n}}</mat-icon>
|
||||
{{'partey.timeslots.filter.type.' + type | i18n}}
|
||||
</mat-option>
|
||||
<mat-select-trigger>
|
||||
<mat-icon inline="true" *ngIf="typeFormControl.value ">{{'partey.timeslots.type.' + typeFormControl.value +
|
||||
'.icon' | i18n}}</mat-icon> {{'partey.timeslots.filter.type.' + (typeFormControl.value ? typeFormControl.value
|
||||
: 'all') | i18n}}
|
||||
</mat-select-trigger>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput [ngxMatDatetimePicker]="afterPicker" [formControl]="afterFormControl"
|
||||
placeholder="{{'partey.timeslots.filter.after' | i18n}}">
|
||||
<mat-datepicker-toggle matSuffix [for]="afterPicker"></mat-datepicker-toggle>
|
||||
<ngx-mat-datetime-picker #afterPicker></ngx-mat-datetime-picker>
|
||||
</mat-form-field>
|
||||
|
||||
<table mat-table matSort [dataSource]="timeslots.content" (matSortChange)="updateSort($event)">
|
||||
<ng-container matColumnDef="starts">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="starts"> {{'partey.timeslots.starts' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let timeslot">{{ timeslot.starts | date:datetimeformat}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="ends">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="ends"> {{'partey.timeslots.ends' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let timeslot"> {{ timeslot.ends | date:datetimeformat}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="title">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="title"> {{'partey.timeslots.title' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let timeslot"> {{ timeslot.title }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="description">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="description"> {{'partey.timeslots.description' | i18n}}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let timeslot"> {{ timeslot.description }} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="type"> {{'partey.timeslots.type' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let timeslot">
|
||||
<mat-icon inline="true" matTooltip="{{'partey.timeslots.type.' + timeslot.type | i18n}}">
|
||||
{{'partey.timeslots.type.' + timeslot.type + '.icon' | i18n}}</mat-icon>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="stream">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="stream"> {{'partey.timeslots.stream' | i18n}}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let timeslot">
|
||||
<button *ngIf="timeslot.type == 'AUDIO'" mat-raised-button
|
||||
(click)="copySecretToClipboard(timeslot.secret)">{{'partey.timeslots.secret.copy' | i18n}}</button>
|
||||
<span *ngIf="timeslot.type == 'VIDEO'"> {{ timeslot.stream }} </span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="edit">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'partey.timeslots.edit' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let timeslot" class="text-right">
|
||||
<a mat-icon-button>
|
||||
<mat-icon (click)="openEdit(timeslot)">edit</mat-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="delete">
|
||||
<th mat-header-cell *matHeaderCellDef class="align-right"> {{'partey.timeslots.delete' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let timeslot" class="text-right">
|
||||
<a mat-icon-button>
|
||||
<mat-icon (click)="confirmDelete(timeslot)">delete</mat-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="timeslotsColumns"></tr>
|
||||
<tr mat-row *matRowDef="let myRowData; columns: timeslotsColumns"></tr>
|
||||
</table>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="timeslots.totalElements" [pageSize]="timeslots.size"
|
||||
(page)="updatePages($event)" showFirstLastButtons></mat-paginator>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<p>{{'partey.timeslots.info' | i18n}}</p>
|
||||
<p *ngIf="!timeslotsQuota">{{'partey.timeslots.noQuota' | i18n}}</p>
|
||||
<div *ngIf="timeslotsQuota">
|
||||
<p>{{'partey.timeslots.left' | i18n:timeslotsQuota}}</p>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card-actions *ngIf="timeslotsQuota">
|
||||
<button mat-button *ngFor="let type of types" (click)="openCreate(type)">
|
||||
<mat-icon inline="true">{{'partey.timeslots.type.' + type + '.icon' | i18n}}</mat-icon>
|
||||
{{'partey.timeslots.create.' + type | i18n}}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
21
src/app/pages/partey/timeslots/timeslots.component.scss
Normal file
21
src/app/pages/partey/timeslots/timeslots.component.scss
Normal file
@ -0,0 +1,21 @@
|
||||
.mat-header-cell,
|
||||
.mat-cell {
|
||||
&.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-cell .mat-button {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.align-right{
|
||||
display: flex;
|
||||
padding: 21px 0;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.mat-form-field+.mat-form-field {
|
||||
margin-left: 8px;
|
||||
}
|
263
src/app/pages/partey/timeslots/timeslots.compontent.ts
Normal file
263
src/app/pages/partey/timeslots/timeslots.compontent.ts
Normal file
@ -0,0 +1,263 @@
|
||||
import {Component, OnInit, ViewChild, Inject} from '@angular/core';
|
||||
import {Sort} from '@angular/material/sort';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
import {FormBuilder, FormGroup, Validators, NgForm} from '@angular/forms';
|
||||
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
|
||||
import {DatePipe} from '@angular/common';
|
||||
import {FormControl} from '@angular/forms';
|
||||
import {debounceTime} from 'rxjs/operators';
|
||||
import {PageEvent} from '@angular/material/paginator';
|
||||
|
||||
import {ParteyTimeslotsService} from '../../../services/partey.timeslots.service';
|
||||
import {ConfirmDialog} from '../../../ui/confirm/confirm.component';
|
||||
import {I18nService} from './../../../services/i18n.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-partey-timeslots',
|
||||
templateUrl: './timeslots.component.html',
|
||||
styleUrls: ['./timeslots.component.scss']
|
||||
})
|
||||
export class ParteyTimeslotsComponent implements OnInit {
|
||||
|
||||
form: FormGroup;
|
||||
@ViewChild('formDirective') private formDirective: NgForm;
|
||||
timeslotsQuota: number = 0;
|
||||
timeslots: any;
|
||||
timeslot: any = {};
|
||||
success: boolean;
|
||||
working: boolean;
|
||||
datetimeformat: string;
|
||||
page: any = {page: 0, size: 10, sort: "id", desc: false};
|
||||
filter: any = {};
|
||||
pageSizeOptions: number[] = [5, 10, 25, 50];
|
||||
visibilities = ["PRIVATE", "PROTECTED", "PUBLIC"];
|
||||
types = ["VIDEO", "AUDIO"];
|
||||
|
||||
timeslotsColumns = ["type", "starts", "ends", "title", "description", "stream", "edit", "delete"];
|
||||
|
||||
searchFormControl = new FormControl();
|
||||
ownerFormControl = new FormControl();
|
||||
afterFormControl = new FormControl();
|
||||
typeFormControl = new FormControl();
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private parteyTimeslotsService: ParteyTimeslotsService,
|
||||
private i18n: I18nService,
|
||||
private datePipe: DatePipe,
|
||||
private snackBar: MatSnackBar,
|
||||
public dialog: MatDialog) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.datetimeformat = this.i18n.get('format.datetime', []);
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
room: ['', Validators.required],
|
||||
starts: ['', Validators.nullValidator],
|
||||
moderationStarts: ['', Validators.nullValidator],
|
||||
expires: ['', Validators.nullValidator],
|
||||
});
|
||||
|
||||
this.filter.owner = "";
|
||||
this.ownerFormControl.setValue("");
|
||||
this.filter.type = "";
|
||||
this.typeFormControl.setValue("");
|
||||
this.filter.after = new Date().toUTCString();
|
||||
this.afterFormControl.setValue(new Date());
|
||||
|
||||
this.searchFormControl.valueChanges.pipe(debounceTime(500)).subscribe(value => {
|
||||
this.filter.search = value;
|
||||
this.parteyTimeslotsService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.filter).subscribe((data: any) => {
|
||||
this.timeslots = data;
|
||||
}, (error) => {})
|
||||
})
|
||||
this.ownerFormControl.valueChanges.subscribe(value => {
|
||||
this.filter.owner = value;
|
||||
this.parteyTimeslotsService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.filter).subscribe((data: any) => {
|
||||
this.timeslots = data;
|
||||
}, (error) => {})
|
||||
})
|
||||
this.typeFormControl.valueChanges.subscribe(value => {
|
||||
this.filter.type = value;
|
||||
this.parteyTimeslotsService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.filter).subscribe((data: any) => {
|
||||
this.timeslots = data;
|
||||
}, (error) => {})
|
||||
})
|
||||
this.afterFormControl.valueChanges.subscribe((value: Date) => {
|
||||
this.filter.after = value && value.toUTCString() || undefined;
|
||||
this.parteyTimeslotsService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.filter).subscribe((data: any) => {
|
||||
this.timeslots = data;
|
||||
}, (error) => {})
|
||||
})
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.timeslotsQuota = 0;
|
||||
|
||||
this.parteyTimeslotsService.quota().subscribe((data: number) => {
|
||||
this.timeslotsQuota = data;
|
||||
})
|
||||
|
||||
this.parteyTimeslotsService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.filter).subscribe((data: any) => {
|
||||
this.timeslots = data;
|
||||
})
|
||||
}
|
||||
|
||||
updatePages(event: PageEvent) {
|
||||
this.page.page = event.pageIndex;
|
||||
this.page.size = event.pageSize;
|
||||
this.parteyTimeslotsService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.filter).subscribe((data: any) => {
|
||||
this.timeslots = data;
|
||||
}, (error) => {})
|
||||
}
|
||||
|
||||
updateSort(sort: Sort) {
|
||||
if(sort.direction == "") {
|
||||
this.page.sort = "id";
|
||||
this.page.desc = false;
|
||||
} else {
|
||||
this.page.sort = sort.active;
|
||||
this.page.desc = sort.direction == "desc";
|
||||
}
|
||||
this.parteyTimeslotsService.get(this.page.page, this.page.size, this.page.sort, this.page.desc, this.filter).subscribe((data: any) => {
|
||||
this.timeslots = data;
|
||||
}, (error) => {})
|
||||
}
|
||||
|
||||
confirmDelete(timeslot) {
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'partey.timeslots.confirmDelete',
|
||||
'args': [timeslot.title, this.datePipe.transform(new Date(timeslot.starts), this.datetimeformat)]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if(result) {
|
||||
this.parteyTimeslotsService.delete(timeslot.id).subscribe((result: any) => {
|
||||
this.refresh();
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openCreate(type) {
|
||||
const dialogRef = this.dialog.open(ParteyTimeslotDialog, {
|
||||
data: {"type": type ? type : "VIDEO", "visibility": "PROTECTED"},
|
||||
minWidth: '400px'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if(result) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openEdit(timeslot) {
|
||||
const timeslotClone = JSON.parse(JSON.stringify(timeslot));
|
||||
const dialogRef = this.dialog.open(ParteyTimeslotDialog, {
|
||||
data: timeslotClone,
|
||||
minWidth: '400px'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if(result) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
copySecretToClipboard(secret) {
|
||||
const selBox = document.createElement('textarea');
|
||||
selBox.value = secret;
|
||||
document.body.appendChild(selBox);
|
||||
selBox.focus();
|
||||
selBox.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(selBox);
|
||||
this.snackBar.open(this.i18n.get("partey.timeslots.secret.copied", []), this.i18n.get("close", []), {
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-timeslot-dialog',
|
||||
templateUrl: 'timeslot.dialog.html',
|
||||
styleUrls: ['./timeslot.dialog.scss']
|
||||
})
|
||||
export class ParteyTimeslotDialog {
|
||||
|
||||
form: FormGroup;
|
||||
timeslot;
|
||||
|
||||
visibilities = ["PRIVATE", "PROTECTED", "PUBLIC"];
|
||||
types = ["VIDEO", "AUDIO"];
|
||||
|
||||
constructor(
|
||||
private parteyTimeslotsService: ParteyTimeslotsService,
|
||||
private formBuilder: FormBuilder,
|
||||
private dialog: MatDialog,
|
||||
public dialogRef: MatDialogRef<ParteyTimeslotDialog>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
this.timeslot = data;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form = this.formBuilder.group({
|
||||
starts: ['', Validators.required],
|
||||
ends: ['', Validators.required],
|
||||
title: ['', Validators.nullValidator],
|
||||
description: ['', Validators.nullValidator],
|
||||
stream: ['', this.timeslot.type == 'VIDEO' ? Validators.required : Validators.nullValidator],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
create(timeslot) {
|
||||
this.parteyTimeslotsService.create(timeslot).subscribe((result: any) => {
|
||||
this.dialogRef.close(timeslot);
|
||||
}, (error) => {
|
||||
if(error.status == 409) {
|
||||
let errors = {};
|
||||
for(let code of error.error) {
|
||||
errors[code.field] = errors[code.field] || {};
|
||||
errors[code.field][code.code] = true;
|
||||
}
|
||||
|
||||
for(let code in errors) {
|
||||
this.form.get(code).setErrors(errors[code]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
save(timeslot) {
|
||||
this.parteyTimeslotsService.update(timeslot).subscribe((result: any) => {
|
||||
this.dialogRef.close(timeslot);
|
||||
}, (error) => {
|
||||
if(error.status == 409) {
|
||||
let errors = {};
|
||||
for(let code of error.error) {
|
||||
errors[code.field] = errors[code.field] || {};
|
||||
errors[code.field][code.code] = true;
|
||||
}
|
||||
|
||||
for(let code in errors) {
|
||||
this.form.get(code).setErrors(errors[code]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -12,7 +12,22 @@ export class JitsiService {
|
||||
}
|
||||
|
||||
get(page: number, size: number, sort: string, desc: boolean) {
|
||||
const httpParams = new HttpParams().set("page", "" + page).set("size", "" + size).set("sort", sort).set("desc", "" + desc);
|
||||
let httpParams = new HttpParams();
|
||||
if(page != undefined) {
|
||||
httpParams = httpParams.set("page", "" + page);
|
||||
}
|
||||
if(size != undefined) {
|
||||
httpParams = httpParams.set("size", "" + size);
|
||||
}
|
||||
|
||||
if(sort != undefined) {
|
||||
httpParams = httpParams.set("sort", sort);
|
||||
}
|
||||
|
||||
if(desc != undefined) {
|
||||
httpParams = httpParams.set("desc", "" + desc);
|
||||
}
|
||||
|
||||
return this.http.get(environment.apiUrl + "/jitsi/rooms", {params: httpParams});
|
||||
}
|
||||
|
||||
|
22
src/app/services/minetest.accounts.service.ts
Normal file
22
src/app/services/minetest.accounts.service.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
|
||||
import {environment} from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MinetestAccountsService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
get() {
|
||||
return this.http.get(environment.apiUrl + "/minetest/accounts");
|
||||
}
|
||||
|
||||
create(minetestAccount) {
|
||||
return this.http.post(environment.apiUrl + "/minetest/accounts", minetestAccount);
|
||||
}
|
||||
|
||||
}
|
69
src/app/services/partey.timeslots.service.ts
Normal file
69
src/app/services/partey.timeslots.service.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
|
||||
import {environment} from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ParteyTimeslotsService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
get(page: number, size: number, sort: string, desc: boolean, filter : any) {
|
||||
let httpParams = new HttpParams();
|
||||
if(page != undefined) {
|
||||
httpParams = httpParams.set("page", "" + page);
|
||||
}
|
||||
if(size != undefined) {
|
||||
httpParams = httpParams.set("size", "" + size);
|
||||
}
|
||||
|
||||
if(sort != undefined) {
|
||||
httpParams = httpParams.set("sort", sort);
|
||||
}
|
||||
|
||||
if(desc != undefined) {
|
||||
httpParams = httpParams.set("desc", "" + desc);
|
||||
}
|
||||
|
||||
if (filter) {
|
||||
if(filter.owner != undefined && filter.owner != "") {
|
||||
httpParams = httpParams.set("owner", "" + filter.owner);
|
||||
}
|
||||
if(filter.after != undefined && filter.after != "") {
|
||||
httpParams = httpParams.set("after", "" + filter.after);
|
||||
}
|
||||
if(filter.type != undefined && filter.type != "") {
|
||||
httpParams = httpParams.set("type", "" + filter.type);
|
||||
}
|
||||
if(filter.visibility != undefined && filter.visibility != "") {
|
||||
httpParams = httpParams.set("visibility", "" + filter.visibility);
|
||||
}
|
||||
if(filter.search != undefined && filter.search != "") {
|
||||
httpParams = httpParams.set("search", "" + filter.search);
|
||||
}
|
||||
}
|
||||
|
||||
return this.http.get(environment.apiUrl + "/partey/timeslots", {params: httpParams});
|
||||
}
|
||||
|
||||
|
||||
quota() {
|
||||
return this.http.get(environment.apiUrl + "/partey/timeslots/quota");
|
||||
}
|
||||
|
||||
create(timeslot) {
|
||||
return this.http.post(environment.apiUrl + "/partey/timeslots", timeslot);
|
||||
}
|
||||
|
||||
update(timeslot) {
|
||||
return this.http.patch(environment.apiUrl + "/partey/timeslots", timeslot);
|
||||
}
|
||||
|
||||
delete(id) {
|
||||
return this.http.delete(environment.apiUrl + "/partey/timeslots/" + id);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user