feat(import): lego-sets ueber die rebrickable-api uebernehmen
Auf "Neues Set" reicht die Setnummer von der Packung: Name, Jahr, Teile, Minifiguren und Thema kommen aus der API, das Bild wird lokal gespeichert und nicht nur verlinkt. Hersteller und Thema werden bei Bedarf angelegt, ein Oberthema inklusive. Alle Aufrufe laufen serverseitig; der Browser spricht nie mit rebrickable.com. Ohne REBRICKABLE_API_KEY bleibt der Import sichtbar, aber abgeschaltet, mit dem Hinweis, was zu tun ist - von Hand anlegen geht unveraendert. Rebrickable liefert keine Anleitungsdateien. Statt das zu verschleiern, legt der Import einen externen Link auf die LEGO-Serviceseite zur Setnummer an. Nebenbei: src/env.ts behandelt leere Werte jetzt wie nicht gesetzt - ein "BASE_URL=" in der .env fuehrte sonst zum Start-Abbruch mit "Invalid URL" statt zum Standardwert. 14 neue Unit-Tests decken Antwortverarbeitung, Setnummern-Varianten und alle Fehlerfaelle der API ab (404, 401, 429, Netzwerk). Refs Phase 2 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-1
@@ -88,8 +88,25 @@ export type StoredImage = {
|
||||
*/
|
||||
export async function storeImage(file: File, kind: UploadKind, ownerId: string): Promise<StoredImage> {
|
||||
assertSize(file);
|
||||
return storeImageBytes(Buffer.from(await file.arrayBuffer()), kind, ownerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `storeImage`, but for bytes we already hold - for instance an image
|
||||
* the server fetched from an import source. The size limit still applies.
|
||||
*/
|
||||
export async function storeImageBytes(
|
||||
bytes: Buffer,
|
||||
kind: UploadKind,
|
||||
ownerId: string,
|
||||
): Promise<StoredImage> {
|
||||
if (bytes.byteLength === 0) throw new UploadError('Die Datei ist leer.');
|
||||
if (bytes.byteLength > env.MAX_UPLOAD_BYTES) {
|
||||
throw new UploadError(
|
||||
`Das Bild ist größer als ${env.MAX_UPLOAD_MB} MB und wurde nicht übernommen.`,
|
||||
);
|
||||
}
|
||||
|
||||
const bytes = Buffer.from(await file.arrayBuffer());
|
||||
const mime = detectMimeType(bytes);
|
||||
if (!mime || !IMAGE_MIME_TYPES.includes(mime as (typeof IMAGE_MIME_TYPES)[number])) {
|
||||
throw new UploadError('Erlaubt sind nur JPEG-, PNG- und WebP-Bilder.');
|
||||
|
||||
Reference in New Issue
Block a user