feat(community): Datenschicht für Galerie, API und Veröffentlichen
- gallery.ts: Galerie aus Appwrite lesen (Abfragen für Liste, Suche, Cursor, Admin-Filter), getGalleryCard (404 und ungültige ID ergeben null), eigene Veröffentlichungen, Meldungen, Bilder - api.ts: Aufrufe von aircard-api mit JWT (Cache je Nutzer, 10 Minuten, geleert bei Auth-Änderung, genau eine Wiederholung bei 401), ApiError mit code, Netz-/Proxy-Fehler als 503 - publish.ts: rendern, zwei Uploads in gallery-images, API; bei Fehler genau die zwei Dateien dieses Versuchs löschen; normalizeTags - cards.ts: eigenständiges fetchFile(bucketId, fileId); CardsApi.fetchFile bleibt Hülle - appwrite.ts: IDS für gallery, reports, gallery-images Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7bbe0a9fe6
commit
89c86fd578
9 files changed
+1576
-7
No files matched your search
@@ -47,7 +47,7 @@ export interface SaveInput {
|
||||
export const DEFAULT_CARD_NAME = 'Meine Karte';
|
||||
const NAME_MAX = 80;
|
||||
/** Zeilen- und Datei-IDs von Appwrite: höchstens 36 Zeichen, kein Sonderzeichen am Anfang. */
|
||||
const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$/;
|
||||
export const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$/;
|
||||
|
||||
/** Trimmt, fasst Leerraum zusammen und kürzt auf 80 Zeichen (Codepoints); leer ergibt „Meine Karte“. */
|
||||
export function normalizeName(name: string): string {
|
||||
@@ -193,11 +193,13 @@ export function createCardsService(api: CardsApi, userId: () => string) {
|
||||
|
||||
export type CardsService = ReturnType<typeof createCardsService>;
|
||||
|
||||
/** Lädt eine Bilddatei mit Projekt-Header und Cookie (siehe `client.prepareRequest`). */
|
||||
async function fetchFile(fileId: string): Promise<Blob> {
|
||||
/** Lädt eine Bilddatei aus einem Bucket mit Projekt-Header und Cookie (siehe `client.prepareRequest`). */
|
||||
export async function fetchFile(bucketId: string, fileId: string): Promise<Blob> {
|
||||
// Bewusst kein storage.getFileView(): das hängt das Projekt als Query-Parameter an die URL und schickt keinen
|
||||
// Header; so trifft die Anfrage die Traefik-Route für /v1 mit Header nicht. prepareRequest setzt Header und Cookie.
|
||||
const url = new URL(`${APPWRITE_ENDPOINT}/storage/buckets/${IDS.bucket}/files/${encodeURIComponent(fileId)}/view`);
|
||||
const url = new URL(
|
||||
`${APPWRITE_ENDPOINT}/storage/buckets/${encodeURIComponent(bucketId)}/files/${encodeURIComponent(fileId)}/view`,
|
||||
);
|
||||
const { uri, options } = client.prepareRequest('GET', url);
|
||||
const res = await fetch(uri, options);
|
||||
if (!res.ok) {
|
||||
@@ -231,7 +233,8 @@ export function appwriteCardsApi(): CardsApi {
|
||||
deleteFile: async (fileId) => {
|
||||
await storage.deleteFile({ bucketId: IDS.bucket, fileId });
|
||||
},
|
||||
fetchFile,
|
||||
// Die privaten Karten liegen im Karten-Bucket; die Galerie holt ihre Bilder über `fetchFile` mit eigenem Bucket.
|
||||
fetchFile: (fileId) => fetchFile(IDS.bucket, fileId),
|
||||
createRow: (data, permissions) =>
|
||||
tables.createRow<TableRow>({ ...target, rowId: ID.unique(), data, permissions }),
|
||||
// Beim Ändern bleiben die Rechte der Zeile unangetastet.
|
||||
|
||||
Reference in new issue
Block a user