Authentication with firebase, Landing Page 1.Teil

This commit is contained in:
2025-01-18 23:00:45 +00:00
parent d17578d123
commit 83035a6b82
25 changed files with 5612 additions and 3008 deletions

View File

@@ -1,28 +1,18 @@
// decks.controller.ts
import express from 'express';
import {
Controller,
Get,
Post,
Delete,
Body,
Param,
Query,
Put,
HttpException,
HttpStatus,
Res,
} from '@nestjs/common';
import { Body, Controller, Delete, Get, HttpException, HttpStatus, Param, Post, Put, Request, UseGuards } from '@nestjs/common';
import { User } from '../db/schema';
import { AuthGuard } from '../service/auth.guard';
import { DrizzleService } from './drizzle.service';
import { firstValueFrom } from 'rxjs';
@Controller('decks')
@UseGuards(AuthGuard)
export class DecksController {
constructor(private readonly drizzleService: DrizzleService) {}
@Get()
async getDecks() {
const entries = await this.drizzleService.getDecks();
async getDecks(@Request() req) {
const user: User = req['user'];
const entries = await this.drizzleService.getDecks(user);
const decks = {};
for (const entry of entries) {
const deckname = entry.deckname!!;
@@ -55,16 +45,18 @@ export class DecksController {
}
@Post()
async createDeck(@Body() data: { deckname: string }) {
async createDeck(@Request() req, @Body() data: { deckname: string }) {
if (!data.deckname) {
throw new HttpException('No deckname provided', HttpStatus.BAD_REQUEST);
}
return this.drizzleService.createDeck(data.deckname);
const user: User = req['user'];
return this.drizzleService.createDeck(data.deckname, user);
}
@Get(':deckname')
async getDeck(@Param('deckname') deckname: string) {
const entries = await this.drizzleService.getDeckByName(deckname);
async getDeck(@Request() req, @Param('deckname') deckname: string) {
const user: User = req['user'];
const entries = await this.drizzleService.getDeckByName(deckname, user);
if (entries.length === 0) {
throw new HttpException('Deck not found', HttpStatus.NOT_FOUND);
}
@@ -98,40 +90,36 @@ export class DecksController {
}
@Delete(':deckname')
async deleteDeck(@Param('deckname') deckname: string) {
return this.drizzleService.deleteDeck(deckname);
async deleteDeck(@Request() req, @Param('deckname') deckname: string) {
const user: User = req['user'];
return this.drizzleService.deleteDeck(deckname, user);
}
@Put(':oldDeckname/rename')
async renameDeck(
@Param('oldDeckname') oldDeckname: string,
@Body() data: { newDeckName: string },
) {
async renameDeck(@Request() req, @Param('oldDeckname') oldDeckname: string, @Body() data: { newDeckName: string }) {
if (!data.newDeckName) {
throw new HttpException('New deck name is required', HttpStatus.BAD_REQUEST);
}
return this.drizzleService.renameDeck(oldDeckname, data.newDeckName);
const user: User = req['user'];
return this.drizzleService.renameDeck(oldDeckname, data.newDeckName, user);
}
@Post('image')
async updateImage(@Body() data: any) {
async updateImage(@Request() req, @Body() data: any) {
if (!data) {
throw new HttpException('No data provided', HttpStatus.BAD_REQUEST);
}
const user: User = req['user'];
const requiredFields = ['deckname', 'bildname', 'bildid', 'boxes'];
if (!requiredFields.every((field) => field in data)) {
if (!requiredFields.every(field => field in data)) {
throw new HttpException('Missing fields in data', HttpStatus.BAD_REQUEST);
}
if (!Array.isArray(data.boxes) || data.boxes.length === 0) {
throw new HttpException(
"'boxes' must be a non-empty list",
HttpStatus.BAD_REQUEST,
);
throw new HttpException("'boxes' must be a non-empty list", HttpStatus.BAD_REQUEST);
}
return this.drizzleService.updateImage(data);
return this.drizzleService.updateImage(data, user);
}
@Delete('image/:bildid')
@@ -140,10 +128,7 @@ export class DecksController {
}
@Post('images/:bildid/move')
async moveImage(
@Param('bildid') bildid: string,
@Body() data: { targetDeckId: string },
) {
async moveImage(@Param('bildid') bildid: string, @Body() data: { targetDeckId: string }) {
if (!data.targetDeckId) {
throw new HttpException('No targetDeckId provided', HttpStatus.BAD_REQUEST);
}
@@ -165,6 +150,4 @@ export class DecksController {
) {
return this.drizzleService.updateBox(boxId, data);
}
}
}

View File

@@ -1,75 +1,63 @@
// drizzle.service.ts
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { and, eq, isNull } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/libsql';
import { Deck, InsertDeck } from '../db/schema';
import { eq, and, isNull } from 'drizzle-orm';
import { Deck, User } from '../db/schema';
@Injectable()
export class DrizzleService {
private db = drizzle('file:local.db');
async getDecks() {
return this.db.select().from(Deck).all();
async getDecks(user: User) {
return this.db.select().from(Deck).where(eq(Deck.user, user.email));
}
async createDeck(deckname: string) {
const result = await this.db.insert(Deck).values({ deckname }).returning();
async createDeck(deckname: string, user: User) {
const result = await this.db.insert(Deck).values({ deckname, user: user.email }).returning();
return { status: 'success', deck: result };
}
async getDeckByName(deckname: string) {
return this.db.select().from(Deck).where(eq(Deck.deckname, deckname)).all();
async getDeckByName(deckname: string, user: User) {
return this.db
.select()
.from(Deck)
.where(and(eq(Deck.deckname, deckname), eq(Deck.user, user.email)));
}
async deleteDeck(deckname: string) {
const existingDeck = await this.getDeckByName(deckname);
async deleteDeck(deckname: string, user: User) {
const existingDeck = await this.getDeckByName(deckname, user);
if (existingDeck.length === 0) {
throw new HttpException('Deck not found', HttpStatus.NOT_FOUND);
}
await this.db.delete(Deck).where(eq(Deck.deckname, deckname));
await this.db.delete(Deck).where(and(eq(Deck.deckname, deckname), eq(Deck.user, user.email)));
return { status: 'success' };
}
async renameDeck(oldDeckname: string, newDeckname: string) {
const existingDeck = await this.getDeckByName(oldDeckname);
async renameDeck(oldDeckname: string, newDeckname: string, user: User) {
const existingDeck = await this.getDeckByName(oldDeckname, user);
if (existingDeck.length === 0) {
throw new HttpException('Deck not found', HttpStatus.NOT_FOUND);
}
const existingNewDeck = await this.getDeckByName(newDeckname);
const existingNewDeck = await this.getDeckByName(newDeckname, user);
if (existingNewDeck.length > 0) {
throw new HttpException(
'Deck with the new name already exists',
HttpStatus.CONFLICT,
);
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(eq(Deck.deckname, oldDeckname));
return { status: 'success', message: 'Deck renamed successfully' };
}
async updateImage(data: {
deckname: string;
bildname: string;
bildid: string;
boxes: Array<{ x1: number; x2: number; y1: number; y2: number }>;
}) {
const existingDeck = await this.getDeckByName(data.deckname);
async updateImage(data: { deckname: string; bildname: string; bildid: string; boxes: Array<{ x1: number; x2: number; y1: number; y2: number }> }, user: User) {
const existingDeck = await this.getDeckByName(data.deckname, user);
if (existingDeck.length === 0) {
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)));
const insertedImages:any = [];
const insertedImages: any = [];
for (let index = 0; index < data.boxes.length; index++) {
const box = data.boxes[index];
const result = await this.db
@@ -83,7 +71,9 @@ export class DrizzleService {
x2: box.x2,
y1: box.y1,
y2: box.y2,
}).returning();
user: 'andreas.knuth@gmail.com',
})
.returning();
insertedImages.push(result);
}
@@ -91,17 +81,10 @@ export class DrizzleService {
}
async deleteImagesByBildId(bildid: string) {
const affectedDecks = await this.db
.select({ deckname: Deck.deckname })
.from(Deck)
.where(eq(Deck.bildid, bildid))
.all();
const affectedDecks = await this.db.select({ deckname: Deck.deckname }).from(Deck).where(eq(Deck.bildid, bildid)).all();
if (affectedDecks.length === 0) {
throw new HttpException(
'No entries found for the given image ID',
HttpStatus.NOT_FOUND,
);
throw new HttpException('No entries found for the given image ID', HttpStatus.NOT_FOUND);
}
await this.db.delete(Deck).where(eq(Deck.bildid, bildid));
@@ -110,22 +93,18 @@ export class DrizzleService {
const remainingImages = await this.db
.select()
.from(Deck)
.where(
and(eq(Deck.deckname, deck.deckname), eq(Deck.bildid, bildid)),
)
.where(and(eq(Deck.deckname, deck.deckname), eq(Deck.bildid, bildid)))
.all();
if (remainingImages.length === 0) {
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)))
.all();
if (emptyDeckEntry.length === 0) {
await this.db.insert(Deck).values({ deckname: deck.deckname });
await this.db.insert(Deck).values({ deckname: deck.deckname, user: 'andreas.knuth@gmail.com' });
}
}
}
@@ -137,23 +116,13 @@ export class DrizzleService {
}
async moveImage(bildid: string, targetDeckId: string) {
const existingImages = await this.db
.select()
.from(Deck)
.where(eq(Deck.bildid, bildid))
.all();
const existingImages = await this.db.select().from(Deck).where(eq(Deck.bildid, bildid)).all();
if (existingImages.length === 0) {
throw new HttpException(
'No entries found for the given image ID',
HttpStatus.NOT_FOUND,
);
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(eq(Deck.bildid, bildid));
return { status: 'success', moved_entries: existingImages.length };
}
@@ -174,10 +143,7 @@ export class DrizzleService {
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(eq(Deck.id, boxId));
if (result.rowsAffected === 0) {
throw new HttpException('Box not found', HttpStatus.NOT_FOUND);
@@ -185,4 +151,4 @@ export class DrizzleService {
return { status: 'success' };
}
}
}

View File

@@ -1,79 +1,64 @@
// decks.controller.ts
import { Body, Controller, HttpException, HttpStatus, Post, Res, UseGuards } from '@nestjs/common';
import express from 'express';
import {
Controller,
Get,
Post,
Delete,
Body,
Param,
Query,
Put,
HttpException,
HttpStatus,
Res,
} from '@nestjs/common';
import { DrizzleService } from './drizzle.service';
import { firstValueFrom } from 'rxjs';
import { AuthGuard } from '../service/auth.guard';
@Controller('')
@UseGuards(AuthGuard)
export class ProxyController {
constructor() {}
// --------------------
// --------------------
// 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`;
// @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);
// 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}`);
// }
// // 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();
// // 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';
// }
// // 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 });
// }
// }
// // 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,
) {
async ocrEndpoint(@Body() data: { image: string }, @Res() res: express.Response) {
try {
if (!data || !data.image) {
throw new HttpException('No image provided', HttpStatus.BAD_REQUEST);
}
const response = await fetch('http://localhost:5000/api/ocr', {
method: 'POST',
headers: {
@@ -81,19 +66,16 @@ export class ProxyController {
},
body: JSON.stringify({ image: data.image }),
});
const result = await response.json();
if (!response.ok) {
if (response.status === 400) {
throw new HttpException(result.error, HttpStatus.BAD_REQUEST);
}
throw new HttpException(
result.error || 'OCR processing failed',
HttpStatus.INTERNAL_SERVER_ERROR,
);
throw new HttpException(result.error || 'OCR processing failed', HttpStatus.INTERNAL_SERVER_ERROR);
}
// Bei erfolgreicher Verarbeitung mit Warnung
if (result.warning) {
return res.status(HttpStatus.OK).json({
@@ -101,21 +83,17 @@ export class ProxyController {
debug_dir: result.debug_dir,
});
}
// Bei vollständig erfolgreicher Verarbeitung
return res.status(HttpStatus.OK).json({
status: result.status,
results: result.results,
});
} catch (error) {
if (error instanceof HttpException) {
throw error;
}
throw new HttpException(
'Internal server error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
throw new HttpException('Internal server error', HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
}
}