all repos — weimar @ ab494a4c3e2c99426dd9f18f02bcb3fb7ee678a3

Unnamed repository; edit this file 'description' to name the repository.

web/src/lib/api.ts (view raw)

  1const BASE = '/api';
  2
  3export interface User {
  4	id: number;
  5	username: string;
  6	is_admin: boolean;
  7	created_at: string;
  8	updated_at: string;
  9}
 10
 11export interface Image {
 12	id: number;
 13	filename: string;
 14	storage_path: string;
 15	thumbnail_path: string | null;
 16	uploaded_by: number;
 17	uploader_username: string;
 18	avatar_url: string;
 19	file_size: number;
 20	width: number;
 21	height: number;
 22	mime_type: string;
 23	innate_tags?: string[];
 24	created_at: string;
 25	updated_at: string;
 26	tags: string[];
 27}
 28
 29export interface ImageList {
 30	images: Image[];
 31	total: number;
 32}
 33
 34export interface Tag {
 35	tag: string;
 36	usage_count: number;
 37}
 38
 39export interface TagDetail {
 40	tag: string;
 41	usage_count: number;
 42}
 43
 44export interface ImageDetail extends Image {
 45	tags_detail: TagDetail[];
 46	is_owner: boolean;
 47}
 48
 49export interface CurrentUser {
 50	id: number;
 51	username: string;
 52	is_admin: boolean;
 53	avatar_url: string;
 54	created_at: string;
 55	updated_at: string;
 56}
 57
 58export interface ApiError {
 59	error: string;
 60}
 61
 62async function request<T>(path: string, opts: RequestInit = {}): Promise<T> {
 63	const res = await fetch(BASE + path, {
 64		credentials: 'include',
 65		headers: opts.body instanceof FormData ? {} : { 'Content-Type': 'application/json' },
 66		...opts,
 67	});
 68	if (!res.ok) {
 69		const body = await res.json().catch(() => ({ error: res.statusText }));
 70		throw new Error((body as ApiError).error || `HTTP ${res.status}`);
 71	}
 72	return res.json();
 73}
 74
 75export async function login(username: string, password: string): Promise<User> {
 76	return request<User>('/auth/login', {
 77		method: 'POST',
 78		body: JSON.stringify({ username, password }),
 79	});
 80}
 81
 82export async function register(username: string, password: string): Promise<User> {
 83	return request<User>('/auth/register', {
 84		method: 'POST',
 85		body: JSON.stringify({ username, password }),
 86	});
 87}
 88
 89export async function logout(): Promise<void> {
 90	await request('/auth/logout', { method: 'POST' });
 91}
 92
 93export async function listImages(tags: string[] = [], uploader = '', page = 1, perPage = 50): Promise<ImageList> {
 94	const params = new URLSearchParams();
 95	params.set('page', String(page));
 96	params.set('per_page', String(perPage));
 97	for (const t of tags) {
 98		params.append('tags', t);
 99	}
100	if (uploader) {
101		params.set('uploader', uploader);
102	}
103	return request<ImageList>(`/images?${params}`);
104}
105
106export async function getImage(id: number): Promise<ImageDetail> {
107	return request<ImageDetail>(`/images/${id}`);
108}
109
110export function imageDownloadUrl(id: number): string {
111	return `${BASE}/images/${id}/download`;
112}
113
114export function thumbnailUrl(id: number): string {
115	return `${BASE}/images/${id}/thumbnail`;
116}
117
118export async function uploadImage(file: File, tags: string[]): Promise<Image> {
119	const fd = new FormData();
120	fd.append('file', file);
121	for (const t of tags) {
122		fd.append('tags', t);
123	}
124	return request<Image>('/upload', { method: 'POST', body: fd });
125}
126
127export async function suggestTags(query: string): Promise<Tag[]> {
128	return request<Tag[]>(`/tags/suggest?q=${encodeURIComponent(query)}`);
129}
130
131export async function suggestUploaders(query: string): Promise<Tag[]> {
132	return request<Tag[]>(`/users/suggest?q=${encodeURIComponent(query)}`);
133}
134
135export async function uploadAvatar(file: File): Promise<{ avatar_url: string }> {
136	const fd = new FormData();
137	fd.append('avatar', file);
138	return request<{ avatar_url: string }>('/users/me/avatar', { method: 'POST', body: fd });
139}
140
141export async function getMe(): Promise<CurrentUser> {
142	return request<CurrentUser>('/users/me');
143}
144
145export interface SiteConfig {
146	site_title: string;
147	favicon_url?: string;
148	logo_url?: string;
149}
150
151export async function getConfig(): Promise<SiteConfig> {
152	return request<SiteConfig>('/config');
153}
154
155export async function addTags(imageId: number, tags: string[]): Promise<{ tags_detail: TagDetail[] }> {
156	return request<{ tags_detail: TagDetail[] }>(`/images/${imageId}/tags`, {
157		method: 'POST',
158		body: JSON.stringify({ tags }),
159	});
160}
161
162export async function removeTags(imageId: number, tags: string[]): Promise<{ tags_detail: TagDetail[] }> {
163	return request<{ tags_detail: TagDetail[] }>(`/images/${imageId}/tags`, {
164		method: 'DELETE',
165		body: JSON.stringify({ tags }),
166	});
167}