diff --git a/api/src/app/drizzle.service.ts b/api/src/app/drizzle.service.ts index ef6cb1a..e99977d 100644 --- a/api/src/app/drizzle.service.ts +++ b/api/src/app/drizzle.service.ts @@ -249,4 +249,21 @@ export class DrizzleService { return { status: 'success' }; } + + /** + * Methode zum Abrufen aller eindeutigen Bild-IDs aus der Datenbank + */ + async getDistinctBildIds(user: User): Promise { + try { + const result = await this.db.selectDistinct([Deck.bildid]).from(Deck).all(); + + // Extrahiere die bildid Werte aus dem Ergebnis + const usedIds = result.map((row: any) => row['0']).filter((id: string | null) => id !== null) as string[]; + console.log(usedIds); + return usedIds; + } catch (error) { + this.sqlLogger.logQuery('Error fetching distinct bildids', []); + throw new HttpException(`Fehler beim Abrufen der Bild-IDs - ${error}`, HttpStatus.INTERNAL_SERVER_ERROR); + } + } } diff --git a/api/src/app/proxy.controller.ts b/api/src/app/proxy.controller.ts index 9fbbe42..c7f3a04 100644 --- a/api/src/app/proxy.controller.ts +++ b/api/src/app/proxy.controller.ts @@ -2,11 +2,12 @@ import { Body, Controller, HttpException, HttpStatus, Post, Res, UseGuards } from '@nestjs/common'; import express from 'express'; import { AuthGuard } from '../service/auth.guard'; +import { DrizzleService } from './drizzle.service'; @Controller('') @UseGuards(AuthGuard) export class ProxyController { - constructor() {} + constructor(private readonly drizzleService: DrizzleService) {} // -------------------- // Proxy Endpoints // -------------------- @@ -54,4 +55,50 @@ export class ProxyController { throw new HttpException('Internal server error', HttpStatus.INTERNAL_SERVER_ERROR); } } + + // -------------------- + // Cleanup Endpoint + // -------------------- + @Post('cleanup') + async cleanupEndpoint(@Body() data: { dryrun?: boolean }, @Res() res: express.Response) { + try { + const user = res.req['user']; // Benutzerinformationen aus dem Request + + // 2. Nur Benutzer mit der spezifischen E-Mail dürfen fortfahren + if (user.email !== 'andreas.knuth@gmail.com') { + throw new HttpException('Zugriff verweigert.', HttpStatus.FORBIDDEN); + } + + // 1. Abrufen der distinct bildid aus der Datenbank + const usedIds = await this.drizzleService.getDistinctBildIds(user); + // 3. Verarbeitung des dryrun Parameters + const dryrun = data.dryrun !== undefined ? data.dryrun : true; + if (typeof dryrun !== 'boolean') { + throw new HttpException("'dryrun' muss ein boolescher Wert sein.", HttpStatus.BAD_REQUEST); + } + + // 4. Aufruf des Flask-Backend-Endpunkts + const response = await fetch('http://localhost:5000/api/cleanup', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ dryrun, usedIds }), + }); + + const result = await response.json(); + + if (!response.ok) { + throw new HttpException(result.error || 'Cleanup failed', response.status); + } + + // 5. Rückgabe der Ergebnisse an den Client + return res.status(HttpStatus.OK).json(result); + } catch (error) { + if (error instanceof HttpException) { + throw error; + } + throw new HttpException('Interner Serverfehler', HttpStatus.INTERNAL_SERVER_ERROR); + } + } } diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000..6999bab Binary files /dev/null and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 0000000..bbf06d8 Binary files /dev/null and b/public/favicon-32x32.png differ diff --git a/public/favicon-48x48.png b/public/favicon-48x48.png new file mode 100644 index 0000000..5aa2e9e Binary files /dev/null and b/public/favicon-48x48.png differ diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 9dee6b9..51d1cac 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -11,8 +11,8 @@ import { PopoverService } from './services/popover.service'; template: `
-

Master Your Vocabulary

-

Learn smarter, not harder. Start your journey today.

+

Master Your Learning

+

Learn smarter, not harder. Start your journey today

- - - - - - - diff --git a/src/app/deck-list.component.ts b/src/app/deck-list.component.ts index 9c743e9..3234c59 100644 --- a/src/app/deck-list.component.ts +++ b/src/app/deck-list.component.ts @@ -373,6 +373,9 @@ export class DeckListComponent implements OnInit { const now = new Date(); now.setHours(0, 0, 0, 0); const dueDates = deck.images.flatMap(image => image.boxes.map(box => (box.due ? new Date(box.due * 86400000) : null))); + if (dueDates.includes(null)) { + return now; + } const futureDueDates = dueDates.filter(date => date && date >= now); if (futureDueDates.length > 0) { const nextDate = futureDueDates.reduce((a, b) => (a < b ? a : b)); @@ -383,7 +386,11 @@ export class DeckListComponent implements OnInit { getNextTrainingString(deck: Deck): string { return this.getNextTrainingDate(deck).toLocaleDateString(); } - + // In deiner Component TypeScript Datei + isToday(date: Date): boolean { + const today = new Date(); + return date.getDate() === today.getDate() && date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear(); + } // Methode zur Berechnung der Anzahl der zu bearbeitenden Wörter getWordsToReview(deck: Deck): number { const nextTraining = this.getNextTrainingDate(deck); diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..9d9d1a8 --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/index.html b/src/index.html index 8b958c3..1dff7eb 100644 --- a/src/index.html +++ b/src/index.html @@ -1,13 +1,22 @@ - + - - - Vokabeltraining - - - - - - - + + + Vokabeltraining + + + + + + + + + +