From a11c74b91b838b2d0662ead9b15231c4147e9a83 Mon Sep 17 00:00:00 2001
From: _Bastler <_Bastler@bstly.de>
Date: Thu, 29 Jul 2021 17:41:25 +0200
Subject: [PATCH] update partey timeslots + minetest
---
src/app/app-routing.module.ts | 4 +
src/app/app.module.ts | 8 +-
.../minetest/accounts/accounts.component.html | 43 +++
.../minetest/accounts/accounts.component.scss | 30 ++
.../minetest/accounts/accounts.component.ts | 77 +++++
.../partey/timeslots/timeslot.dialog.html | 48 ++++
.../partey/timeslots/timeslot.dialog.scss | 7 +
.../partey/timeslots/timeslots.component.html | 117 ++++++++
.../partey/timeslots/timeslots.component.scss | 21 ++
.../partey/timeslots/timeslots.compontent.ts | 263 ++++++++++++++++++
src/app/services/jitsi.service.ts | 17 +-
src/app/services/minetest.accounts.service.ts | 22 ++
src/app/services/partey.timeslots.service.ts | 69 +++++
13 files changed, 723 insertions(+), 3 deletions(-)
create mode 100644 src/app/pages/minetest/accounts/accounts.component.html
create mode 100644 src/app/pages/minetest/accounts/accounts.component.scss
create mode 100644 src/app/pages/minetest/accounts/accounts.component.ts
create mode 100644 src/app/pages/partey/timeslots/timeslot.dialog.html
create mode 100644 src/app/pages/partey/timeslots/timeslot.dialog.scss
create mode 100644 src/app/pages/partey/timeslots/timeslots.component.html
create mode 100644 src/app/pages/partey/timeslots/timeslots.component.scss
create mode 100644 src/app/pages/partey/timeslots/timeslots.compontent.ts
create mode 100644 src/app/services/minetest.accounts.service.ts
create mode 100644 src/app/services/partey.timeslots.service.ts
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 99b7358..36b302e 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -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]},
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 3ec8604..6a033dd 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -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: [
diff --git a/src/app/pages/minetest/accounts/accounts.component.html b/src/app/pages/minetest/accounts/accounts.component.html
new file mode 100644
index 0000000..041874e
--- /dev/null
+++ b/src/app/pages/minetest/accounts/accounts.component.html
@@ -0,0 +1,43 @@
+
{{'minetest.accounts' | i18n}}
+
+
+
+
+ {{'minetest.accounts.name' | i18n}} |
+
+ {{minetestAccount.name}}
+ |
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/minetest/accounts/accounts.component.scss b/src/app/pages/minetest/accounts/accounts.component.scss
new file mode 100644
index 0000000..bc6ceb6
--- /dev/null
+++ b/src/app/pages/minetest/accounts/accounts.component.scss
@@ -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;
+}
\ No newline at end of file
diff --git a/src/app/pages/minetest/accounts/accounts.component.ts b/src/app/pages/minetest/accounts/accounts.component.ts
new file mode 100644
index 0000000..d63f8be
--- /dev/null
+++ b/src/app/pages/minetest/accounts/accounts.component.ts
@@ -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;
+ })
+ }
+
+}
diff --git a/src/app/pages/partey/timeslots/timeslot.dialog.html b/src/app/pages/partey/timeslots/timeslot.dialog.html
new file mode 100644
index 0000000..4a51820
--- /dev/null
+++ b/src/app/pages/partey/timeslots/timeslot.dialog.html
@@ -0,0 +1,48 @@
+
+ {{'partey.timeslots.type.' + timeslot.type + '.icon' | i18n}} {{(timeslot.id ? 'partey.timeslots.edit' : 'partey.timeslots.create.' +
+ timeslot.type) | i18n}}
+
+
+ {{'partey.timeslots.type.' + timeslot.type | i18n}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/partey/timeslots/timeslot.dialog.scss b/src/app/pages/partey/timeslots/timeslot.dialog.scss
new file mode 100644
index 0000000..03bec19
--- /dev/null
+++ b/src/app/pages/partey/timeslots/timeslot.dialog.scss
@@ -0,0 +1,7 @@
+mat-form-field {
+ display: block;
+}
+
+mat-slide-toggle {
+ margin-bottom: 24px;
+}
\ No newline at end of file
diff --git a/src/app/pages/partey/timeslots/timeslots.component.html b/src/app/pages/partey/timeslots/timeslots.component.html
new file mode 100644
index 0000000..1581527
--- /dev/null
+++ b/src/app/pages/partey/timeslots/timeslots.component.html
@@ -0,0 +1,117 @@
+{{'partey.timeslots' | i18n}}
+
+
+
+
+
+
+ {{'partey.timeslots.filter.owner' | i18n}}
+
+ {{'partey.timeslots.filter.owner.mine' | i18n}}
+ {{'partey.timeslots.filter.owner.others' | i18n}}
+ {{'partey.timeslots.filter.owner.all' | i18n}}
+
+
+
+ {{'partey.timeslots.filter.type' | i18n}}
+
+ {{'partey.timeslots.filter.type.all' | i18n}}
+
+ {{'partey.timeslots.type.' + type + '.icon' | i18n}}
+ {{'partey.timeslots.filter.type.' + type | i18n}}
+
+
+ {{'partey.timeslots.type.' + typeFormControl.value +
+ '.icon' | i18n}} {{'partey.timeslots.filter.type.' + (typeFormControl.value ? typeFormControl.value
+ : 'all') | i18n}}
+
+
+
+
+
+
+
+
+
+
+
+ {{'partey.timeslots.starts' | i18n}} |
+ {{ timeslot.starts | date:datetimeformat}} |
+
+
+
+ {{'partey.timeslots.ends' | i18n}} |
+ {{ timeslot.ends | date:datetimeformat}} |
+
+
+
+ {{'partey.timeslots.title' | i18n}} |
+ {{ timeslot.title }} |
+
+
+
+ {{'partey.timeslots.description' | i18n}}
+ |
+ {{ timeslot.description }} |
+
+
+
+ {{'partey.timeslots.type' | i18n}} |
+
+
+ {{'partey.timeslots.type.' + timeslot.type + '.icon' | i18n}}
+ |
+
+
+
+ {{'partey.timeslots.stream' | i18n}}
+ |
+
+
+ {{ timeslot.stream }}
+ |
+
+
+
+ {{'partey.timeslots.edit' | i18n}} |
+
+
+ edit
+
+ |
+
+
+
+ {{'partey.timeslots.delete' | i18n}} |
+
+
+ delete
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ {{'partey.timeslots.info' | i18n}}
+ {{'partey.timeslots.noQuota' | i18n}}
+
+
{{'partey.timeslots.left' | i18n:timeslotsQuota}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/partey/timeslots/timeslots.component.scss b/src/app/pages/partey/timeslots/timeslots.component.scss
new file mode 100644
index 0000000..dd47025
--- /dev/null
+++ b/src/app/pages/partey/timeslots/timeslots.component.scss
@@ -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;
+}
diff --git a/src/app/pages/partey/timeslots/timeslots.compontent.ts b/src/app/pages/partey/timeslots/timeslots.compontent.ts
new file mode 100644
index 0000000..84b1c1c
--- /dev/null
+++ b/src/app/pages/partey/timeslots/timeslots.compontent.ts
@@ -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,
+ @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]);
+ }
+ }
+ });
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/app/services/jitsi.service.ts b/src/app/services/jitsi.service.ts
index 0c820b8..ec1dda6 100644
--- a/src/app/services/jitsi.service.ts
+++ b/src/app/services/jitsi.service.ts
@@ -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});
}
diff --git a/src/app/services/minetest.accounts.service.ts b/src/app/services/minetest.accounts.service.ts
new file mode 100644
index 0000000..bed477f
--- /dev/null
+++ b/src/app/services/minetest.accounts.service.ts
@@ -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);
+ }
+
+}
\ No newline at end of file
diff --git a/src/app/services/partey.timeslots.service.ts b/src/app/services/partey.timeslots.service.ts
new file mode 100644
index 0000000..66e0cae
--- /dev/null
+++ b/src/app/services/partey.timeslots.service.ts
@@ -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);
+ }
+
+}
\ No newline at end of file