diff --git a/api/src/app/decks.controller.ts b/api/src/app/decks.controller.ts index 1d0da50..5cf2071 100644 --- a/api/src/app/decks.controller.ts +++ b/api/src/app/decks.controller.ts @@ -123,20 +123,23 @@ export class DecksController { } @Delete('image/:bildid') - async deleteImagesByBildId(@Param('bildid') bildid: string) { - return this.drizzleService.deleteImagesByBildId(bildid); + async deleteImagesByBildId(@Request() req, @Param('bildid') bildid: string) { + const user: User = req['user']; + return this.drizzleService.deleteImagesByBildId(bildid, user); } @Post('images/:bildid/move') - async moveImage(@Param('bildid') bildid: string, @Body() data: { targetDeckId: string }) { + async moveImage(@Request() req, @Param('bildid') bildid: string, @Body() data: { targetDeckId: string }) { if (!data.targetDeckId) { throw new HttpException('No targetDeckId provided', HttpStatus.BAD_REQUEST); } - return this.drizzleService.moveImage(bildid, data.targetDeckId); + const user: User = req['user']; + return this.drizzleService.moveImage(bildid, data.targetDeckId, user); } @Put('boxes/:boxId') async updateBox( + @Request() req, @Param('boxId') boxId: number, @Body() data: { @@ -148,6 +151,7 @@ export class DecksController { isGraduated?: boolean; }, ) { - return this.drizzleService.updateBox(boxId, data); + const user: User = req['user']; + return this.drizzleService.updateBox(boxId, data, user); } } diff --git a/api/src/app/drizzle.service.ts b/api/src/app/drizzle.service.ts index 0279dee..a375177 100644 --- a/api/src/app/drizzle.service.ts +++ b/api/src/app/drizzle.service.ts @@ -45,7 +45,10 @@ export class DrizzleService { throw new HttpException('Deck with the new name already exists', HttpStatus.CONFLICT); } - await this.db.update(Deck).set({ deckname: newDeckname }).where(eq(Deck.deckname, oldDeckname)); + await this.db + .update(Deck) + .set({ deckname: newDeckname }) + .where(and(eq(Deck.deckname, oldDeckname), eq(Deck.user, user.email))); return { status: 'success', message: 'Deck renamed successfully' }; } @@ -55,7 +58,7 @@ export class DrizzleService { throw new HttpException('Deck not found', HttpStatus.NOT_FOUND); } - await this.db.delete(Deck).where(and(eq(Deck.deckname, data.deckname), eq(Deck.bildid, data.bildid))); + await this.db.delete(Deck).where(and(eq(Deck.deckname, data.deckname), eq(Deck.bildid, data.bildid), eq(Deck.user, user.email))); const insertedImages: any = []; for (let index = 0; index < data.boxes.length; index++) { @@ -71,7 +74,7 @@ export class DrizzleService { x2: box.x2, y1: box.y1, y2: box.y2, - user: 'andreas.knuth@gmail.com', + user: user.email, }) .returning(); insertedImages.push(result); @@ -80,14 +83,18 @@ export class DrizzleService { return { status: 'success', inserted_images: insertedImages }; } - async deleteImagesByBildId(bildid: string) { - const affectedDecks = await this.db.select({ deckname: Deck.deckname }).from(Deck).where(eq(Deck.bildid, bildid)).all(); + async deleteImagesByBildId(bildid: string, user: User) { + const affectedDecks = await this.db + .select({ deckname: Deck.deckname }) + .from(Deck) + .where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))) + .all(); if (affectedDecks.length === 0) { throw new HttpException('No entries found for the given image ID', HttpStatus.NOT_FOUND); } - await this.db.delete(Deck).where(eq(Deck.bildid, bildid)); + await this.db.delete(Deck).where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))); for (const deck of affectedDecks) { const remainingImages = await this.db @@ -100,11 +107,11 @@ export class DrizzleService { const emptyDeckEntry = await this.db .select() .from(Deck) - .where(and(eq(Deck.deckname, deck.deckname), isNull(Deck.bildid))) + .where(and(eq(Deck.deckname, deck.deckname), isNull(Deck.bildid), eq(Deck.user, user.email))) .all(); if (emptyDeckEntry.length === 0) { - await this.db.insert(Deck).values({ deckname: deck.deckname, user: 'andreas.knuth@gmail.com' }); + await this.db.insert(Deck).values({ deckname: deck.deckname, user: user.email }); } } } @@ -115,14 +122,21 @@ export class DrizzleService { }; } - async moveImage(bildid: string, targetDeckId: string) { - const existingImages = await this.db.select().from(Deck).where(eq(Deck.bildid, bildid)).all(); + async moveImage(bildid: string, targetDeckId: string, user: User) { + const existingImages = await this.db + .select() + .from(Deck) + .where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))) + .all(); if (existingImages.length === 0) { throw new HttpException('No entries found for the given image ID', HttpStatus.NOT_FOUND); } - await this.db.update(Deck).set({ deckname: targetDeckId }).where(eq(Deck.bildid, bildid)); + await this.db + .update(Deck) + .set({ deckname: targetDeckId }) + .where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))); return { status: 'success', moved_entries: existingImages.length }; } @@ -137,13 +151,17 @@ export class DrizzleService { lapses?: number; isGraduated?: boolean; }, + user: User, ) { const updateData: any = { ...data }; if (typeof data.isGraduated === 'boolean') { updateData.isGraduated = Number(data.isGraduated); } - const result = await this.db.update(Deck).set(updateData).where(eq(Deck.id, boxId)); + const result = await this.db + .update(Deck) + .set(updateData) + .where(and(eq(Deck.id, boxId), eq(Deck.user, user.email))); if (result.rowsAffected === 0) { throw new HttpException('Box not found', HttpStatus.NOT_FOUND); diff --git a/api/src/app/proxy.controller.ts b/api/src/app/proxy.controller.ts index 728de60..9fbbe42 100644 --- a/api/src/app/proxy.controller.ts +++ b/api/src/app/proxy.controller.ts @@ -10,48 +10,6 @@ export class ProxyController { // -------------------- // Proxy Endpoints // -------------------- - // @Get('debug_image/:name/:filename') - // async getDebugImage( - // @Param('name') name: string, - // @Param('filename') filename: string, - // @Res() res: express.Response, - // ) { - // const url = `http://localhost:8080/api/debug_image/${name}/${filename}`; - // //const url = `http://localhost:5000/api/debug_image/20250112_112306_9286e3bf/thumbnail.jpg`; - - // try { - // // Fetch the image from the external service - // const response = await fetch(url); - - // // Check if the response is OK (status code 200-299) - // if (!response.ok) { - // throw new Error(`Failed to retrieve image: ${response.statusText}`); - // } - - // // Get the image data as a buffer - // const imageBuffer = await response.arrayBuffer(); - - // // Determine the Content-Type based on the file extension - // let contentType = 'image/png'; // Default MIME type - // if (filename.toLowerCase().endsWith('.jpg') || filename.toLowerCase().endsWith('.jpeg')) { - // contentType = 'image/jpeg'; - // } else if (filename.toLowerCase().endsWith('.gif')) { - // contentType = 'image/gif'; - // } else if (filename.toLowerCase().endsWith('.bmp')) { - // contentType = 'image/bmp'; - // } else if (filename.toLowerCase().endsWith('.tiff') || filename.toLowerCase().endsWith('.tif')) { - // contentType = 'image/tiff'; - // } - - // // Set the Content-Type header and send the image data - // res.set('Content-Type', contentType); - // res.send(Buffer.from(imageBuffer)); - // } catch (error) { - // // Handle errors - // res.status(500).json({ error: error.message }); - // } - // } - @Post('ocr') async ocrEndpoint(@Body() data: { image: string }, @Res() res: express.Response) { try { diff --git a/src/app/deck-list.component.ts b/src/app/deck-list.component.ts index fc1f5ba..67d12b6 100644 --- a/src/app/deck-list.component.ts +++ b/src/app/deck-list.component.ts @@ -69,6 +69,9 @@ export class DeckListComponent implements OnInit { if (!this.activeDeck && this.decks.length > 0) { this.activeDeck = this.decks[0]; } + if (this.decks.length === 0) { + this.activeDeck = null; + } }, error: err => console.error('Error loading decks', err), }); @@ -100,7 +103,7 @@ export class DeckListComponent implements OnInit { next: () => { this.loadDecks(); this.closeDeletePopover(); - this.activeDeck = this.decks[0]; + this.activeDeck = this.decks.length > 0 ? this.decks[0] : null; }, error: err => console.error('Error deleting deck', err), }); @@ -314,7 +317,21 @@ export class DeckListComponent implements OnInit { // Handler for the moveCompleted event onImageMoved(): void { this.imageToMove = null; - this.loadDecks(); + // Speichere den Namen des aktiven Decks + const activeDeckName = this.activeDeck?.name; + + this.deckService.getDecks().subscribe({ + next: decks => { + this.decks = decks; + // Aktualisiere den activeDeck mit den neuen Daten + if (activeDeckName) { + this.activeDeck = this.decks.find(deck => deck.name === activeDeckName) || null; + } + // Force change detection + this.cdr.detectChanges(); + }, + error: err => console.error('Error loading decks', err), + }); } onFileChange(event: any): void {