Fix birthday -1 bug

Add lite configuration
Add registration deletion
Add favicon
Add dynamic title
This commit is contained in:
Artur Savitskiy 2024-05-21 00:38:01 +02:00
parent 504f0293ac
commit bb6751c649
15 changed files with 121 additions and 18 deletions

View File

@ -0,0 +1,31 @@
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
require_once('../../utils/config.php');
require_once('../../utils/db.php');
require_once('../../utils/strings.php');
$authorization = $_SERVER["HTTP_AUTHORIZATION"];
if(strcmp($authorization, INTERNAL_API_KEY) !== 0) {
echo 'STOP TRYING TO STEAL MY DATA!';
exit;
}
$method = $_SERVER['REQUEST_METHOD'];
if ('POST' === $method) {
parse_str(file_get_contents('php://input'), $_POST);
}
$connection = connect();
$rid = intval($_POST["rid"]);
$querystr = "DELETE FROM li_registrations WHERE rid=${rid}";
mysqli_query($connection, $querystr);
echo json_encode('{ "result": "true" }');
?>

View File

@ -199,7 +199,7 @@ function sendRegistrationMail($data) {
$message = " $message = "
<html><head><title>Neue Anmeldung bei Li-Dance</title></head><body> <html><head><title>Neue Anmeldung bei Li-Dance</title></head><body>
<p>{$data->firstname} {$data->lastname} aus {$data->city} hat sich angemeldet.</p> <p>{$data->firstname} {$data->lastname} aus {$data->city} hat sich angemeldet.</p>
<p>Btte bearbeite diese möglichst schnell: <a href='" . REGISTRATION_URL . "'>Zur Anmeldung</a></p> <p>Btte bearbeite diese m&ouml;glichst schnell: <a href='" . REGISTRATION_URL . "'>Zur Anmeldung</a></p>
</body></html>"; </body></html>";
$header[] = 'MIME-Version: 1.0'; $header[] = 'MIME-Version: 1.0';

View File

@ -58,6 +58,27 @@
], ],
"outputHashing": "all" "outputHashing": "all"
}, },
"lite": {
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "2mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.lite.ts"
}
],
"outputHashing": "all"
},
"development": { "development": {
"buildOptimizer": false, "buildOptimizer": false,
"optimization": false, "optimization": false,

View File

@ -5,8 +5,13 @@ import { VisitsComponent } from './components/visits/visits.component';
import { VisitsDatetimeComponent } from './components/visits/visits-datetime/visits-datetime.component'; import { VisitsDatetimeComponent } from './components/visits/visits-datetime/visits-datetime.component';
import { RegistrationWizardComponent } from './components/registrations/registration-wizard/registration-wizard.component'; import { RegistrationWizardComponent } from './components/registrations/registration-wizard/registration-wizard.component';
import { RegistrationListComponent } from './components/registrations/registration-list/registration-list.component'; import { RegistrationListComponent } from './components/registrations/registration-list/registration-list.component';
import { environment } from 'src/environments/environment';
const routes: Routes = [ const publicRoutes: Routes = [
{ path: '**', component: RegistrationWizardComponent },
];
const internalRoutes: Routes = [
{ path: 'students', component: StudentListComponent }, { path: 'students', component: StudentListComponent },
{ path: 'visits', component: VisitsComponent }, { path: 'visits', component: VisitsComponent },
{ path: 'registrations', component: RegistrationListComponent }, { path: 'registrations', component: RegistrationListComponent },
@ -16,6 +21,9 @@ const routes: Routes = [
{ path: '**', redirectTo: 'students' }, { path: '**', redirectTo: 'students' },
]; ];
//const routes: Routes = publicRoutes;
const routes: Routes = environment.lite ? publicRoutes : internalRoutes;
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(routes)], imports: [RouterModule.forRoot(routes)],
exports: [RouterModule], exports: [RouterModule],

View File

@ -1,5 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon'; import { MatIconRegistry } from '@angular/material/icon';
import { Title } from '@angular/platform-browser';
import { environment } from 'src/environments/environment';
@Component({ @Component({
selector: 'li-root', selector: 'li-root',
@ -9,12 +11,14 @@ import { MatIconRegistry } from '@angular/material/icon';
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
constructor( constructor(
private matIconReg: MatIconRegistry private matIconReg: MatIconRegistry,
private titleService: Title
) {} ) {}
title = 'li-dance-backoffice'; title = 'li-dance-backoffice';
ngOnInit(): void { ngOnInit(): void {
this.matIconReg.setDefaultFontSetClass('material-symbols-outlined'); this.matIconReg.setDefaultFontSetClass('material-symbols-outlined');
this.titleService.setTitle(environment.appTitle);
} }
} }

View File

@ -23,11 +23,17 @@
<ng-container matColumnDef="Gender"> <ng-container matColumnDef="Gender">
<mat-header-cell *matHeaderCellDef> Geschlecht </mat-header-cell> <mat-header-cell *matHeaderCellDef> Geschlecht </mat-header-cell>
<mat-cell *matCellDef="let element">{{element.gender}}</mat-cell> <mat-cell *matCellDef="let element">{{element | gender}}</mat-cell>
</ng-container> </ng-container>
<ng-container matColumnDef="Address">
<mat-header-cell *matHeaderCellDef> Adresse </mat-header-cell>
<mat-cell *matCellDef="let element">{{element | address}}</mat-cell>
</ng-container>
<ng-container matColumnDef="Actions"> <ng-container matColumnDef="Actions">
<mat-header-cell *matHeaderCellDef></mat-header-cell> <mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let element" class="actions"><mat-icon>delete</mat-icon></mat-cell> <mat-cell *matCellDef="let element" class="actions"><mat-icon (click)="delete(element)">delete</mat-icon></mat-cell>
</ng-container> </ng-container>
<mat-header-row <mat-header-row
@ -36,6 +42,7 @@
'Lastname', 'Lastname',
'Birthday', 'Birthday',
'Gender', 'Gender',
'Address',
'Actions' 'Actions'
]"></mat-header-row> ]"></mat-header-row>
<mat-row <mat-row
@ -46,6 +53,7 @@
'Lastname', 'Lastname',
'Birthday', 'Birthday',
'Gender', 'Gender',
'Address',
'Actions' 'Actions'
] ]
"></mat-row> "></mat-row>

View File

@ -41,6 +41,10 @@ export class RegistrationListComponent implements OnInit {
this.dataSource.filter = filterValue.trim().toLowerCase(); this.dataSource.filter = filterValue.trim().toLowerCase();
} }
public delete(registration: StudentRegistration): void {
this.registrationsService.del(registration).subscribe(_ => this.getData());
}
private getData() { private getData() {
this.registrationsService.get().subscribe({ this.registrationsService.get().subscribe({
next: registrations => { next: registrations => {

View File

@ -1,10 +1,11 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { Student } from '../models/student'; import { Student } from '../models/student';
import { StudentRegistration } from '../models/student-registration';
@Pipe({ name: 'address' }) @Pipe({ name: 'address' })
export class AddressPipe implements PipeTransform { export class AddressPipe implements PipeTransform {
transform(student: Student): string { transform(student: Student | StudentRegistration): string {
let result = `${student.street} ${student.house}${student.house_suffix}, ${student.zip} ${student.city}`; let result = `${student.street} ${student.house}, ${student.zip} ${student.city}`;
return result.trim() === '0,' ? '' : result; return result.trim() === '0,' ? '' : result;
} }
} }

View File

@ -1,14 +1,18 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
import { Student } from '../models/student'; import { Student } from '../models/student';
import { StudentRegistration } from '../models/student-registration';
@Pipe({ name: 'gender' }) @Pipe({ name: 'gender' })
export class GenderPipe implements PipeTransform { export class GenderPipe implements PipeTransform {
transform(student: Student): string { transform(student: Student | StudentRegistration): string {
console.log(student);
switch (Number(student.gender)) { switch (Number(student.gender)) {
case 0: case 0:
return 'M'; return 'M';
case 1: case 1:
return 'W'; return 'W';
case 2:
return 'D';
default: default:
return '?'; return '?';
} }

View File

@ -3,28 +3,28 @@ import { HttpClient, HttpHeaders } from "@angular/common/http";
import { StudentRegistration } from "../../models/student-registration"; import { StudentRegistration } from "../../models/student-registration";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
import { environment } from 'src/environments/environment'; import { environment } from 'src/environments/environment';
import * as moment from 'moment';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class RegistrationsService { export class RegistrationsService {
private readonly serviceName = 'registrations'; private readonly serviceName = 'registrations';
private readonly headers = { headers: new HttpHeaders({ "Authorization": environment.apiKeyPublic })}; private readonly publicHeaders = { headers: new HttpHeaders({ "Authorization": environment.apiKeyPublic })};
private readonly internalHeaders = { headers: new HttpHeaders({ "Authorization": environment.apiKeyInternal })};
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
public get(): Observable<StudentRegistration[]> { public get(): Observable<StudentRegistration[]> {
return this.http.get<StudentRegistration[]>( return this.http.get<StudentRegistration[]>(
`${environment.apiUrl}${this.serviceName}/get.php`, this.headers `${environment.apiUrl}${this.serviceName}/get.php`, this.internalHeaders
); );
} }
public set(registration: StudentRegistration): Observable<void> { public set(registration: StudentRegistration): Observable<void> {
const formatDate = (date: Date): string => date.toISOString().split('T')[0];
const payload = `firstname=${encodeURIComponent(registration.firstName)}&` + const payload = `firstname=${encodeURIComponent(registration.firstName)}&` +
`lastname=${encodeURIComponent(registration.lastName)}&` + `lastname=${encodeURIComponent(registration.lastName)}&` +
`birthday=${encodeURIComponent(formatDate(registration.birthday))}&` + `birthday=${encodeURIComponent(moment(registration.birthday).format('YYYY-MM-DD'))}&` +
`gender=${encodeURIComponent(registration.gender)}&` + `gender=${encodeURIComponent(registration.gender)}&` +
`street=${encodeURIComponent(registration.street)}&` + `street=${encodeURIComponent(registration.street)}&` +
`house=${encodeURIComponent(registration.house)}&` + `house=${encodeURIComponent(registration.house)}&` +
@ -43,11 +43,20 @@ export class RegistrationsService {
`returnDebitConsent=${encodeURIComponent(registration.returnDebitConsent)}&` + `returnDebitConsent=${encodeURIComponent(registration.returnDebitConsent)}&` +
`dataStorageConsent=${encodeURIComponent(registration.dataStorageConsent)}&` + `dataStorageConsent=${encodeURIComponent(registration.dataStorageConsent)}&` +
`multimediaConsent=${encodeURIComponent(registration.multimediaConsent)}`; `multimediaConsent=${encodeURIComponent(registration.multimediaConsent)}`;
return this.http.post<void>(`${environment.apiUrl}${this.serviceName}/set.php`, return this.http.post<void>(`${environment.apiUrl}${this.serviceName}/set.php`,
payload, payload,
this.headers this.publicHeaders
); );
} }
public del(registration: StudentRegistration): Observable<void> {
const payload = `rid=${registration.rid}`;
return this.http.post<void>(
`${environment.apiUrl}${this.serviceName}/del.php`,
payload,
this.internalHeaders
);
}
} }

View File

@ -0,0 +1,8 @@
export const environment = {
production: true,
lite: true,
appTitle: 'Li-Dance Registration',
apiUrl: 'https://li-dance.de/plan/api/',
apiKeyPublic: '754259b6-caf0-4eca-a1f6-812731adae79',
apiKeyInternal: '',
};

View File

@ -1,5 +1,7 @@
export const environment = { export const environment = {
production: true, production: true,
lite: false,
appTitle: 'Li-Dance Backoffice Suite',
apiUrl: 'https://li-dance.de/plan/api/', apiUrl: 'https://li-dance.de/plan/api/',
apiKeyPublic: '754259b6-caf0-4eca-a1f6-812731adae79', apiKeyPublic: '754259b6-caf0-4eca-a1f6-812731adae79',
apiKeyInternal: '1ca6fc7d-d5b8-473c-a44d-a8c9098e2940', apiKeyInternal: '1ca6fc7d-d5b8-473c-a44d-a8c9098e2940',

View File

@ -4,6 +4,8 @@
export const environment = { export const environment = {
production: false, production: false,
lite: false,
appTitle: 'Li-Dance Backoffice Suite',
apiUrl: 'https://li-dance.de/plan/api/', apiUrl: 'https://li-dance.de/plan/api/',
apiKeyPublic: '754259b6-caf0-4eca-a1f6-812731adae79', apiKeyPublic: '754259b6-caf0-4eca-a1f6-812731adae79',
apiKeyInternal: '1ca6fc7d-d5b8-473c-a44d-a8c9098e2940', apiKeyInternal: '1ca6fc7d-d5b8-473c-a44d-a8c9098e2940',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 B

View File

@ -2,10 +2,11 @@
<html lang="de"> <html lang="de">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>Li-Dance Backoffice</title> <title></title>
<base href="/" /> <base href="./" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" /> <link rel="shortcut icon" href="/files/cto_layout/img/favicon-32x32.png" type="image/x-icon">
<link rel="apple-touch-icon" href="/files/cto_layout/img/favicon-32x32.png">
<link rel="preconnect" href="https://fonts.gstatic.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" />
<link <link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap"