import { inject, Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { firstValueFrom, map, tap } from 'rxjs'; import { EndpointService } from './EndpointService'; import { ImageView } from '../models/ImageView.model'; import { SliceView } from '../models/SliceView.model'; import { QueryParams } from '../models/Query.model'; import { QueryClient, QueryOptions, queryOptions } from '@tanstack/angular-query-experimental'; import { ImageViewWithBlobUrl } from '../client-models/ImageViewWithBlobUrl'; @Injectable({ providedIn: 'root', }) export class ImageService { public static ImageProps = [ 'id', 'created', 'modified', 'userFilename', 'mimeType', 'alt', 'caption', 'objectName', 'height', 'width', 'owner', 'viewers', ] as const; private readonly httpClient = inject(HttpClient); private readonly endpointService = inject(EndpointService); private readonly queryClient = inject(QueryClient); public getOwnedImages(queryParams?: QueryParams): Promise> { return firstValueFrom( this.httpClient.get>(this.endpointService.getUrl('images', [], queryParams)), ); } public getImageViewWithBlobUrl(imageView: ImageView): Promise { return firstValueFrom( this.httpClient .get(this.endpointService.getUrl('images', [imageView.owner.username, imageView.filename]), { responseType: 'blob', }) .pipe( map((blob) => URL.createObjectURL(blob)), map( (blobUrl) => ({ ...imageView, blobUrl, }) satisfies ImageViewWithBlobUrl, ), ), ); } public getImage( imageView: ImageView, ): QueryOptions { return queryOptions({ queryKey: ['image-views-with-blob-urls', imageView.owner.username, imageView.filename], queryFn: () => this.getImageViewWithBlobUrl(imageView), }); } public uploadImage( image: File, filename?: string, alt?: string, caption?: string, isPublic?: boolean, ): Promise { const formData = new FormData(); formData.append('image', image); formData.append('filename', filename ?? image.name); if (alt) { formData.append('alt', alt); } if (caption) { formData.append('caption', caption); } if (isPublic !== undefined) { formData.append('isPublic', isPublic.toString()); } return firstValueFrom( this.httpClient.post(this.endpointService.getUrl('images'), formData).pipe( tap(async () => { await this.queryClient.invalidateQueries({ queryKey: ['image-views'], }); }), ), ); } public imageExists(username: string, filename: string): Promise { return firstValueFrom( this.httpClient .get<{ exists: boolean }>(this.endpointService.getUrl('images', [username, filename, 'exists'])) .pipe(map((view) => view.exists)), ); } public deleteImage(username: string, filename: string): Promise { return firstValueFrom( this.httpClient.delete(this.endpointService.getUrl('images', [username, filename])).pipe( tap(async () => { await this.queryClient.refetchQueries({ queryKey: ['image-views', username, filename], }); await this.queryClient.refetchQueries({ queryKey: ['image-views-with-blob-urls', username, filename], }); }), ), ); } public updateImage( username: string, filename: string, data: { alt?: string | null; caption?: string | null; isPublic?: boolean | null; viewersToAdd?: string[] | null; viewersToRemove?: string[] | null; clearAllViewers?: boolean | null; }, ): Promise { return firstValueFrom( this.httpClient.put(this.endpointService.getUrl('images', [username, filename]), data).pipe( tap(async () => { await this.queryClient.refetchQueries({ queryKey: ['image-views', username, filename], }); await this.queryClient.refetchQueries({ queryKey: ['image-views-with-blob-urls', username, filename], }); }), ), ); } }