Files
beavergram/frontend/src/lib/api/shares.ts
T

120 lines
3.2 KiB
TypeScript

import { request } from "$lib/api/client";
import type { FileShare, FileShareHit, ShareSubject } from "$lib/api/types";
import { accounts } from "$lib/stores/accounts.svelte";
export interface ShareSettings {
expiresInSeconds: number | null;
keepExpiry?: boolean;
maxDownloads: number | null;
}
function subjectQuery(subject: ShareSubject): Record<string, number | string> {
const query: Record<string, number | string> = { kind: subject.kind };
if (subject.mediaId !== undefined) {
query.media_id = subject.mediaId;
}
if (subject.versionId !== undefined) {
query.version_id = subject.versionId;
}
if (subject.peerId !== undefined) {
query.peer_id = subject.peerId;
}
if (subject.storyId !== undefined) {
query.story_id = subject.storyId;
}
return query;
}
export function listShares(activeOnly = false): Promise<FileShare[]> {
return request<FileShare[]>("/shares", {
account: true,
query: { active_only: activeOnly, limit: 200 },
});
}
export function lookupShare(subject: ShareSubject): Promise<FileShare | null> {
return request<FileShare | null>("/shares/lookup", {
account: true,
query: subjectQuery(subject),
});
}
export function createShare(
subject: ShareSubject,
settings: ShareSettings
): Promise<FileShare> {
return request<FileShare>("/shares", {
method: "POST",
body: {
account_id: accounts.selectedId,
kind: subject.kind,
media_id: subject.mediaId ?? null,
version_id: subject.versionId ?? null,
peer_id: subject.peerId ?? null,
story_id: subject.storyId ?? null,
expires_in_seconds: settings.expiresInSeconds,
max_downloads: settings.maxDownloads,
},
});
}
export function updateShare(
id: number,
settings: ShareSettings
): Promise<FileShare> {
return request<FileShare>(`/shares/${id}`, {
method: "PATCH",
body: {
expires_in_seconds: settings.expiresInSeconds,
keep_expiry: settings.keepExpiry ?? false,
max_downloads: settings.maxDownloads,
},
});
}
export function revokeShare(id: number): Promise<FileShare> {
return request<FileShare>(`/shares/${id}/revoke`, { method: "POST" });
}
export function reissueShare(id: number): Promise<FileShare> {
return request<FileShare>(`/shares/${id}/reissue`, { method: "POST" });
}
export function deleteShare(id: number): Promise<void> {
return request<void>(`/shares/${id}`, { method: "DELETE" });
}
export function listShareHits(id: number): Promise<FileShareHit[]> {
return request<FileShareHit[]>(`/shares/${id}/hits`, {
query: { limit: 50 },
});
}
const TRAILING_SLASH = /\/$/;
export function shareUrl(share: FileShare): string {
const origin =
typeof window === "undefined"
? ""
: window.location.origin.replace(TRAILING_SLASH, "");
return `${origin}/f/${share.token}`;
}
export function shareState(
share: FileShare
): "active" | "revoked" | "expired" | "exhausted" {
if (share.revoked_at) {
return "revoked";
}
if (share.expires_at && Date.parse(share.expires_at) <= Date.now()) {
return "expired";
}
if (
share.max_downloads !== null &&
share.download_count >= share.max_downloads
) {
return "exhausted";
}
return "active";
}