part ok
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { getDatabase } from '../client';
|
||||
import { getSession } from '../session';
|
||||
import { newResourceId } from '../id';
|
||||
import { FILE_COLUMNS_SQL } from '../schema';
|
||||
import { getDeviceUserId } from './preferences';
|
||||
@@ -6,6 +6,7 @@ import type { FileEntry, FileRow, StoredFile, SyncStatus } from '../types';
|
||||
|
||||
export type SaveFileOptions = {
|
||||
syncStatus?: SyncStatus;
|
||||
resource_id?: string;
|
||||
};
|
||||
|
||||
export async function saveFile(
|
||||
@@ -13,15 +14,20 @@ export async function saveFile(
|
||||
folderResourceId: string,
|
||||
options: SaveFileOptions = {},
|
||||
): Promise<StoredFile> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const now = Date.now();
|
||||
const exists = file.exists ? 1 : 0;
|
||||
const ownerId = await getDeviceUserId();
|
||||
|
||||
const existing = await db.getFirstAsync<FileRow>(
|
||||
`SELECT ${FILE_COLUMNS_SQL} FROM files WHERE uri = ?`,
|
||||
file.uri,
|
||||
);
|
||||
const existing = options.resource_id
|
||||
? await db.getFirstAsync<FileRow>(
|
||||
`SELECT ${FILE_COLUMNS_SQL} FROM files WHERE resource_id = ?`,
|
||||
options.resource_id,
|
||||
)
|
||||
: await db.getFirstAsync<FileRow>(
|
||||
`SELECT ${FILE_COLUMNS_SQL} FROM files WHERE uri = ?`,
|
||||
file.uri,
|
||||
);
|
||||
|
||||
const resourceId = existing?.resource_id ?? (await newResourceId());
|
||||
const baseSync = existing?.sync_status ?? options.syncStatus ?? 'local';
|
||||
@@ -64,7 +70,7 @@ export async function saveFile(
|
||||
}
|
||||
|
||||
export async function getFiles(folderResourceId?: string): Promise<StoredFile[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const rows =
|
||||
folderResourceId === undefined
|
||||
? await db.getAllAsync<FileRow>(`SELECT ${FILE_COLUMNS_SQL} FROM files ORDER BY name ASC`)
|
||||
@@ -76,7 +82,7 @@ export async function getFiles(folderResourceId?: string): Promise<StoredFile[]>
|
||||
}
|
||||
|
||||
export async function getFile(resourceId: string): Promise<StoredFile | null> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<FileRow>(
|
||||
`SELECT ${FILE_COLUMNS_SQL} FROM files WHERE resource_id = ?`,
|
||||
resourceId,
|
||||
@@ -85,7 +91,7 @@ export async function getFile(resourceId: string): Promise<StoredFile | null> {
|
||||
}
|
||||
|
||||
export async function removeFile(resourceId: string): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync('DELETE FROM files WHERE resource_id = ?', resourceId);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDatabase } from '../client';
|
||||
import { getSession } from '../session';
|
||||
import { newResourceId } from '../id';
|
||||
import { FOLDER_COLUMNS_SQL } from '../schema';
|
||||
import { getDeviceUserId } from './preferences';
|
||||
@@ -20,21 +20,21 @@ export async function saveFolder(
|
||||
input: SaveFolderInput,
|
||||
options: SaveFolderOptions = {},
|
||||
): Promise<StoredFolder> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const now = Date.now();
|
||||
const exists =
|
||||
input.exists === undefined || input.exists === null ? null : input.exists ? 1 : 0;
|
||||
const ownerId = await getDeviceUserId();
|
||||
|
||||
const existing = input.uri
|
||||
const existing = input.resource_id
|
||||
? await db.getFirstAsync<FolderRow>(
|
||||
`SELECT ${FOLDER_COLUMNS_SQL} FROM folders WHERE uri = ?`,
|
||||
input.uri,
|
||||
`SELECT ${FOLDER_COLUMNS_SQL} FROM folders WHERE resource_id = ?`,
|
||||
input.resource_id,
|
||||
)
|
||||
: input.resource_id
|
||||
: input.uri
|
||||
? await db.getFirstAsync<FolderRow>(
|
||||
`SELECT ${FOLDER_COLUMNS_SQL} FROM folders WHERE resource_id = ?`,
|
||||
input.resource_id,
|
||||
`SELECT ${FOLDER_COLUMNS_SQL} FROM folders WHERE uri = ?`,
|
||||
input.uri,
|
||||
)
|
||||
: null;
|
||||
|
||||
@@ -82,7 +82,7 @@ export async function saveDirectory(folder: {
|
||||
}
|
||||
|
||||
export async function getFolders(): Promise<StoredFolder[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const rows = await db.getAllAsync<FolderRow>(
|
||||
`SELECT ${FOLDER_COLUMNS_SQL} FROM folders ORDER BY name ASC`,
|
||||
);
|
||||
@@ -92,7 +92,7 @@ export async function getFolders(): Promise<StoredFolder[]> {
|
||||
export async function getFolderFolders(
|
||||
parentResourceId: string | null,
|
||||
): Promise<StoredFolder[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const rows = await db.getAllAsync<FolderRow>(
|
||||
`SELECT ${FOLDER_COLUMNS_SQL} FROM folders WHERE parent_resource_id IS ? ORDER BY name ASC`,
|
||||
parentResourceId,
|
||||
@@ -101,7 +101,7 @@ export async function getFolderFolders(
|
||||
}
|
||||
|
||||
export async function getFolder(resourceId: string): Promise<StoredFolder | null> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<FolderRow>(
|
||||
`SELECT ${FOLDER_COLUMNS_SQL} FROM folders WHERE resource_id = ?`,
|
||||
resourceId,
|
||||
@@ -110,7 +110,7 @@ export async function getFolder(resourceId: string): Promise<StoredFolder | null
|
||||
}
|
||||
|
||||
export async function removeFolder(resourceId: string): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync('DELETE FROM folders WHERE resource_id = ?', resourceId);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDatabase } from '../client';
|
||||
import { getSession } from '../session';
|
||||
import type {
|
||||
NewPendingOperation,
|
||||
PendingOperation,
|
||||
@@ -13,10 +13,12 @@ const PENDING_OPERATION_COLUMNS = `
|
||||
const MAX_BACKOFF_MS = 24 * 60 * 60 * 1000;
|
||||
const BASE_BACKOFF_MS = 30 * 1000;
|
||||
|
||||
export const MAX_PENDING_ATTEMPTS = 5;
|
||||
|
||||
export async function enqueuePendingOperation(
|
||||
operation: NewPendingOperation,
|
||||
): Promise<number> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<{ id: number }>(
|
||||
`INSERT INTO pending_operations
|
||||
(resource_id, resource_type, ref_type, ref_id, operation, payload, status, attempts, created_at)
|
||||
@@ -36,7 +38,7 @@ export async function enqueuePendingOperation(
|
||||
export async function getPendingOperations(
|
||||
status?: PendingOperationStatus,
|
||||
): Promise<PendingOperation[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const rows = status
|
||||
? await db.getAllAsync<PendingOperationRow>(
|
||||
`SELECT ${PENDING_OPERATION_COLUMNS} FROM pending_operations
|
||||
@@ -51,7 +53,7 @@ export async function getPendingOperations(
|
||||
}
|
||||
|
||||
export async function getNextQueuedOperation(): Promise<PendingOperation | null> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<PendingOperationRow>(
|
||||
`SELECT ${PENDING_OPERATION_COLUMNS} FROM pending_operations
|
||||
WHERE status = 'pending'
|
||||
@@ -68,7 +70,7 @@ export async function markPendingOperation(
|
||||
status: PendingOperationStatus,
|
||||
error?: string | null,
|
||||
): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const now = Date.now();
|
||||
|
||||
if (status === 'failed') {
|
||||
@@ -78,12 +80,23 @@ export async function markPendingOperation(
|
||||
);
|
||||
if (!current) return;
|
||||
const attempts = current.attempts + 1;
|
||||
if (attempts >= MAX_PENDING_ATTEMPTS) {
|
||||
await db.runAsync(
|
||||
`UPDATE pending_operations SET
|
||||
status = 'failed', attempts = ?, error = ?, next_retry_at = NULL, last_error_at = ?
|
||||
WHERE id = ?`,
|
||||
attempts,
|
||||
error ?? null,
|
||||
now,
|
||||
id,
|
||||
);
|
||||
return;
|
||||
}
|
||||
const backoff = Math.min(BASE_BACKOFF_MS * 2 ** attempts, MAX_BACKOFF_MS);
|
||||
await db.runAsync(
|
||||
`UPDATE pending_operations SET
|
||||
status = ?, attempts = ?, error = ?, next_retry_at = ?, last_error_at = ?
|
||||
status = 'pending', attempts = ?, error = ?, next_retry_at = ?, last_error_at = ?
|
||||
WHERE id = ?`,
|
||||
status,
|
||||
attempts,
|
||||
error ?? null,
|
||||
now + backoff,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { SQLiteDatabase } from 'expo-sqlite';
|
||||
import { getDatabase } from '../client';
|
||||
import type { DbSession } from '../session';
|
||||
import { getSession } from '../session';
|
||||
import { PERMISSION_TTL_MS } from '../schema';
|
||||
import { getDeviceUserId } from './preferences';
|
||||
import type {
|
||||
@@ -29,6 +29,7 @@ export type AccessCheck = {
|
||||
|
||||
type LineageNode = {
|
||||
resource_id: string;
|
||||
resource_type: ResourceType;
|
||||
parent_resource_id: string | null;
|
||||
owner_id: string;
|
||||
};
|
||||
@@ -41,7 +42,7 @@ export async function getResourcePermission(
|
||||
resourceId: string,
|
||||
resourceType: ResourceType,
|
||||
): Promise<ResourcePermission | null> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<ResourcePermissionRow>(
|
||||
`SELECT * FROM resource_permissions WHERE resource_id = ? AND resource_type = ?`,
|
||||
resourceId,
|
||||
@@ -53,7 +54,7 @@ export async function getResourcePermission(
|
||||
export async function saveResourcePermission(
|
||||
permission: NewResourcePermission,
|
||||
): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const now = Date.now();
|
||||
await db.runAsync(
|
||||
`INSERT INTO resource_permissions
|
||||
@@ -83,21 +84,32 @@ async function resourceLineage(
|
||||
resourceId: string,
|
||||
resourceType: ResourceType,
|
||||
): Promise<LineageNode[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
|
||||
const anchor = await db.getFirstAsync<{ folder_resource_id: string }>(
|
||||
'SELECT folder_resource_id FROM files WHERE resource_id = ?',
|
||||
resourceId,
|
||||
);
|
||||
if (resourceType === 'file') {
|
||||
if (!anchor) return [];
|
||||
return folderLineage(db, anchor.folder_resource_id);
|
||||
const file = await db.getFirstAsync<{
|
||||
folder_resource_id: string;
|
||||
owner_id: string;
|
||||
}>(
|
||||
'SELECT folder_resource_id, owner_id FROM files WHERE resource_id = ?',
|
||||
resourceId,
|
||||
);
|
||||
if (!file) return [];
|
||||
return [
|
||||
{
|
||||
resource_id: resourceId,
|
||||
resource_type: 'file',
|
||||
parent_resource_id: file.folder_resource_id,
|
||||
owner_id: file.owner_id,
|
||||
},
|
||||
...(await folderLineage(db, file.folder_resource_id)),
|
||||
];
|
||||
}
|
||||
return folderLineage(db, resourceId);
|
||||
}
|
||||
|
||||
async function folderLineage(
|
||||
db: SQLiteDatabase,
|
||||
db: DbSession,
|
||||
startResourceId: string,
|
||||
): Promise<LineageNode[]> {
|
||||
const rows = await db.getAllAsync<LineageNode>(
|
||||
@@ -108,34 +120,18 @@ async function folderLineage(
|
||||
FROM folders f
|
||||
JOIN lineage l ON f.resource_id = l.parent_resource_id
|
||||
)
|
||||
SELECT resource_id, parent_resource_id, owner_id FROM lineage`,
|
||||
SELECT resource_id, 'folder' AS resource_type, parent_resource_id, owner_id FROM lineage`,
|
||||
startResourceId,
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
|
||||
function decideFromPermission(
|
||||
permission: ResourcePermission,
|
||||
required: AccessLevel,
|
||||
now: number,
|
||||
): AccessCheck {
|
||||
if (permission.expiresAt != null && permission.expiresAt < now) {
|
||||
return {
|
||||
allowed: false,
|
||||
access: permission.effectiveAccess,
|
||||
source: 'cache',
|
||||
stale: false,
|
||||
expiresAt: permission.expiresAt,
|
||||
};
|
||||
}
|
||||
const granted = rank(permission.effectiveAccess) >= rank(required);
|
||||
return {
|
||||
allowed: granted,
|
||||
access: permission.effectiveAccess,
|
||||
source: 'cache',
|
||||
stale: now - permission.cachedAt > PERMISSION_TTL_MS,
|
||||
expiresAt: permission.expiresAt,
|
||||
};
|
||||
function isStale(cachedAt: number, now: number): boolean {
|
||||
return now - cachedAt > PERMISSION_TTL_MS;
|
||||
}
|
||||
|
||||
function readOnlyAccess(permission: ResourcePermission, now: number): AccessLevel {
|
||||
return isStale(permission.cachedAt, now) ? 'viewer' : permission.effectiveAccess;
|
||||
}
|
||||
|
||||
export async function canAccess(
|
||||
@@ -143,28 +139,75 @@ export async function canAccess(
|
||||
resourceType: ResourceType,
|
||||
required: AccessLevel,
|
||||
): Promise<AccessCheck> {
|
||||
const db = await getDatabase();
|
||||
const now = Date.now();
|
||||
const deviceUserId = await getDeviceUserId();
|
||||
|
||||
const cached = await getResourcePermission(resourceId, resourceType);
|
||||
if (cached) return decideFromPermission(cached, required, now);
|
||||
const exactCache = await getResourcePermission(resourceId, resourceType);
|
||||
if (exactCache) {
|
||||
if (exactCache.expiresAt != null && exactCache.expiresAt < now) {
|
||||
return {
|
||||
allowed: false,
|
||||
access: exactCache.effectiveAccess,
|
||||
source: 'cache',
|
||||
stale: false,
|
||||
expiresAt: exactCache.expiresAt,
|
||||
};
|
||||
}
|
||||
const stale = isStale(exactCache.cachedAt, now);
|
||||
const applyAccess = readOnlyAccess(exactCache, now);
|
||||
return {
|
||||
allowed: rank(applyAccess) >= rank(required),
|
||||
access: applyAccess,
|
||||
source: 'cache',
|
||||
stale,
|
||||
expiresAt: exactCache.expiresAt,
|
||||
};
|
||||
}
|
||||
|
||||
const lineage = await resourceLineage(resourceId, resourceType);
|
||||
for (const node of lineage) {
|
||||
let best: {
|
||||
access: AccessLevel;
|
||||
source: AccessSource;
|
||||
stale: boolean;
|
||||
expiresAt: number | null;
|
||||
} | null = null;
|
||||
|
||||
for (const [index, node] of lineage.entries()) {
|
||||
if (node.owner_id === deviceUserId) {
|
||||
return { allowed: true, access: 'owner', source: 'owner', stale: false, expiresAt: null };
|
||||
}
|
||||
const nodePermission = await getResourcePermission(node.resource_id, 'folder');
|
||||
if (nodePermission) {
|
||||
const decision = decideFromPermission(nodePermission, required, now);
|
||||
if (decision.source === 'cache') {
|
||||
return { ...decision, source: 'inherited' };
|
||||
}
|
||||
|
||||
const nodePermission = await getResourcePermission(node.resource_id, node.resource_type);
|
||||
if (!nodePermission) continue;
|
||||
if (nodePermission.expiresAt != null && nodePermission.expiresAt < now) continue;
|
||||
if (index > 0 && nodePermission.inherit === false) continue;
|
||||
|
||||
const stale = isStale(nodePermission.cachedAt, now);
|
||||
const candidate = {
|
||||
access: readOnlyAccess(nodePermission, now),
|
||||
source: (index === 0 ? 'cache' : 'inherited') as AccessSource,
|
||||
stale,
|
||||
expiresAt: nodePermission.expiresAt,
|
||||
};
|
||||
if (
|
||||
!best ||
|
||||
rank(candidate.access) > rank(best.access) ||
|
||||
(rank(candidate.access) === rank(best.access) && !candidate.stale && best.stale)
|
||||
) {
|
||||
best = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return { allowed: false, access: null, source: 'none', stale: false, expiresAt: null };
|
||||
if (!best) {
|
||||
return { allowed: false, access: null, source: 'none', stale: false, expiresAt: null };
|
||||
}
|
||||
return {
|
||||
allowed: rank(best.access) >= rank(required),
|
||||
access: best.access,
|
||||
source: best.source,
|
||||
stale: best.stale,
|
||||
expiresAt: best.expiresAt,
|
||||
};
|
||||
}
|
||||
|
||||
export async function canWrite(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDatabase } from '../client';
|
||||
import { getSession } from '../session';
|
||||
import { DEVICE_USER_ID_KEY, PREFERENCES_KEY } from '../schema';
|
||||
import type { UserPreferences } from '../types';
|
||||
|
||||
@@ -7,7 +7,7 @@ const DEFAULT_PREFERENCES: UserPreferences = {
|
||||
};
|
||||
|
||||
export async function getDeviceUserId(): Promise<string> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<{ value: string }>(
|
||||
'SELECT "value" FROM user_preferences WHERE "key" = ?',
|
||||
DEVICE_USER_ID_KEY,
|
||||
@@ -28,7 +28,7 @@ export async function getDeviceUserId(): Promise<string> {
|
||||
}
|
||||
|
||||
export async function saveUserPreferences(preferences: UserPreferences): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync(
|
||||
`INSERT INTO user_preferences ("key", "value", updated_at) VALUES (?, ?, ?)
|
||||
ON CONFLICT("key") DO UPDATE SET "value" = excluded."value", updated_at = excluded.updated_at`,
|
||||
@@ -39,7 +39,7 @@ export async function saveUserPreferences(preferences: UserPreferences): Promise
|
||||
}
|
||||
|
||||
export async function getUserPreferences(): Promise<UserPreferences> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<{ value: string }>(
|
||||
'SELECT "value" FROM user_preferences WHERE "key" = ?',
|
||||
PREFERENCES_KEY,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDatabase } from '../client';
|
||||
import { getSession } from '../session';
|
||||
import type { Recipient, RecipientRow, RecipientType } from '../types';
|
||||
|
||||
export async function saveRecipient(
|
||||
@@ -6,7 +6,7 @@ export async function saveRecipient(
|
||||
recipientId: string,
|
||||
displayName: string,
|
||||
): Promise<Recipient> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync(
|
||||
`INSERT INTO recipients (recipient_type, recipient_id, display_name, is_active, updated_at)
|
||||
VALUES (?, ?, ?, 1, ?)
|
||||
@@ -28,7 +28,7 @@ export async function saveRecipient(
|
||||
}
|
||||
|
||||
export async function getRecipients(activeOnly = true): Promise<Recipient[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const rows = activeOnly
|
||||
? await db.getAllAsync<RecipientRow>(
|
||||
'SELECT * FROM recipients WHERE is_active = 1 ORDER BY display_name ASC',
|
||||
@@ -42,7 +42,7 @@ export async function setRecipientActive(
|
||||
recipientId: string,
|
||||
active: boolean,
|
||||
): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync(
|
||||
`UPDATE recipients SET is_active = ?, updated_at = ?
|
||||
WHERE recipient_type = ? AND recipient_id = ?`,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDatabase } from '../client';
|
||||
import { getSession } from '../session';
|
||||
import type { NewShareLink, ResourceType, ShareLink, ShareLinkRow } from '../types';
|
||||
|
||||
const PUSH_STATUS_SQL = `(
|
||||
@@ -16,7 +16,7 @@ const PUSH_STATUS_SQL = `(
|
||||
) AS push_status`;
|
||||
|
||||
export async function createShareLink(input: NewShareLink): Promise<ShareLink> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const now = Date.now();
|
||||
|
||||
let token = input.token;
|
||||
@@ -49,7 +49,7 @@ export async function createShareLink(input: NewShareLink): Promise<ShareLink> {
|
||||
}
|
||||
|
||||
export async function getShareLinkById(id: number): Promise<ShareLink | null> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<ShareLinkRow & { push_status: ShareLink['pushStatus'] }>(
|
||||
`SELECT sl.*, ${PUSH_STATUS_SQL} FROM share_links sl WHERE sl.id = ?`,
|
||||
id,
|
||||
@@ -58,7 +58,7 @@ export async function getShareLinkById(id: number): Promise<ShareLink | null> {
|
||||
}
|
||||
|
||||
export async function getShareLinkByToken(token: string): Promise<ShareLink | null> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<ShareLinkRow & { push_status: ShareLink['pushStatus'] }>(
|
||||
`SELECT sl.*, ${PUSH_STATUS_SQL} FROM share_links sl WHERE sl.token = ?`,
|
||||
token,
|
||||
@@ -70,7 +70,7 @@ export async function getShareLinks(
|
||||
resourceId?: string,
|
||||
resourceType?: ResourceType,
|
||||
): Promise<ShareLink[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
let sql = `SELECT sl.*, ${PUSH_STATUS_SQL} FROM share_links sl`;
|
||||
const params: string[] = [];
|
||||
if (resourceId) {
|
||||
@@ -87,7 +87,7 @@ export async function getShareLinks(
|
||||
}
|
||||
|
||||
export async function incrementLinkDownloads(id: number): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync(
|
||||
`UPDATE share_links SET downloads_count = downloads_count + 1, updated_at = ? WHERE id = ?`,
|
||||
Date.now(),
|
||||
@@ -96,7 +96,7 @@ export async function incrementLinkDownloads(id: number): Promise<void> {
|
||||
}
|
||||
|
||||
export async function revokeShareLink(id: number): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync(
|
||||
`UPDATE share_links SET is_revoked = 1, updated_at = ? WHERE id = ?`,
|
||||
Date.now(),
|
||||
@@ -108,7 +108,7 @@ export async function removeShareLinksForResource(
|
||||
resourceId: string,
|
||||
resourceType: ResourceType,
|
||||
): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync('DELETE FROM share_links WHERE resource_id = ? AND resource_type = ?', resourceId, resourceType);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getDatabase } from '../client';
|
||||
import { getSession } from '../session';
|
||||
import type { NewShare, ResourceType, Share, ShareRow } from '../types';
|
||||
|
||||
const PUSH_STATUS_SQL = `(
|
||||
@@ -16,7 +16,7 @@ const PUSH_STATUS_SQL = `(
|
||||
) AS push_status`;
|
||||
|
||||
export async function saveShare(share: NewShare): Promise<Share> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const now = Date.now();
|
||||
|
||||
await db.runAsync(
|
||||
@@ -56,7 +56,7 @@ export async function getShare(
|
||||
recipientType: 'user' | 'group',
|
||||
recipientId: string,
|
||||
): Promise<Share | null> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
const row = await db.getFirstAsync<ShareRow & { push_status: Share['pushStatus'] }>(
|
||||
`SELECT s.*, ${PUSH_STATUS_SQL} FROM shares s
|
||||
WHERE s.resource_id = ? AND s.resource_type = ? AND s.recipient_type = ? AND s.recipient_id = ?`,
|
||||
@@ -72,7 +72,7 @@ export async function getShares(
|
||||
resourceId?: string,
|
||||
resourceType?: ResourceType,
|
||||
): Promise<Share[]> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
let sql = `SELECT s.*, ${PUSH_STATUS_SQL} FROM shares s`;
|
||||
const params: string[] = [];
|
||||
if (resourceId) {
|
||||
@@ -94,7 +94,7 @@ export async function removeShare(
|
||||
recipientType: 'user' | 'group',
|
||||
recipientId: string,
|
||||
): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync(
|
||||
`DELETE FROM shares
|
||||
WHERE resource_id = ? AND resource_type = ? AND recipient_type = ? AND recipient_id = ?`,
|
||||
@@ -109,7 +109,7 @@ export async function removeSharesForResource(
|
||||
resourceId: string,
|
||||
resourceType: ResourceType,
|
||||
): Promise<void> {
|
||||
const db = await getDatabase();
|
||||
const db = await getSession();
|
||||
await db.runAsync('DELETE FROM shares WHERE resource_id = ? AND resource_type = ?', resourceId, resourceType);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user