mirror of
https://github.com/get-drexa/drive.git
synced 2025-11-30 21:41:39 +00:00
- Replace Err.Code with ErrorCode throughout convex model files - Update error() function calls to use new signature - Remove unused Err namespace imports Co-authored-by: Ona <no-reply@ona.com>
211 lines
4.9 KiB
TypeScript
211 lines
4.9 KiB
TypeScript
import { ConvexError, v } from "convex/values"
|
|
import {
|
|
apiKeyAuthenticatedQuery,
|
|
authenticatedMutation,
|
|
authenticatedQuery,
|
|
authorizedGet,
|
|
} from "./functions"
|
|
import * as Directories from "./model/directories"
|
|
import * as Files from "./model/files"
|
|
import * as FileSystem from "./model/filesystem"
|
|
import {
|
|
deleteItemsPermanently,
|
|
emptyTrash as emptyTrashImpl,
|
|
fetchFileUrl as fetchFileUrlImpl,
|
|
restoreItems as restoreItemsImpl,
|
|
VDirectoryHandle,
|
|
VFileSystemHandle,
|
|
} from "./model/filesystem"
|
|
import { createErrorData, ErrorCode, error } from "./shared/error"
|
|
import type {
|
|
DirectoryHandle,
|
|
FileHandle,
|
|
FileSystemHandle,
|
|
FileSystemItem,
|
|
} from "./shared/filesystem"
|
|
import { FileType } from "./shared/filesystem"
|
|
|
|
export const moveItems = authenticatedMutation({
|
|
args: {
|
|
targetDirectory: VDirectoryHandle,
|
|
items: v.array(VFileSystemHandle),
|
|
},
|
|
handler: async (ctx, { targetDirectory: targetDirectoryHandle, items }) => {
|
|
const targetDirectory = await authorizedGet(
|
|
ctx,
|
|
targetDirectoryHandle.id,
|
|
)
|
|
if (!targetDirectory) {
|
|
error({
|
|
code: ErrorCode.NotFound,
|
|
message: `Directory ${targetDirectoryHandle.id} not found`,
|
|
})
|
|
}
|
|
|
|
const directoryHandles: DirectoryHandle[] = []
|
|
const fileHandles: FileHandle[] = []
|
|
for (const item of items) {
|
|
switch (item.kind) {
|
|
case FileType.Directory:
|
|
directoryHandles.push(item)
|
|
break
|
|
case FileType.File:
|
|
fileHandles.push(item)
|
|
break
|
|
}
|
|
}
|
|
|
|
const [fileMoveResult, directoryMoveResult] = await Promise.all([
|
|
Files.move(ctx, {
|
|
targetDirectory: targetDirectoryHandle,
|
|
items: fileHandles,
|
|
}),
|
|
Directories.move(ctx, {
|
|
targetDirectory: targetDirectoryHandle,
|
|
sourceDirectories: directoryHandles,
|
|
}),
|
|
])
|
|
|
|
return {
|
|
moved: [...directoryMoveResult.moved, ...fileMoveResult.moved],
|
|
errors: [...fileMoveResult.errors, ...directoryMoveResult.errors],
|
|
}
|
|
},
|
|
})
|
|
|
|
export const moveToTrash = authenticatedMutation({
|
|
args: {
|
|
handles: v.array(VFileSystemHandle),
|
|
},
|
|
handler: async (ctx, { handles }) => {
|
|
for (const handle of handles) {
|
|
const item = await authorizedGet(ctx, handle.id)
|
|
if (!item) {
|
|
error({
|
|
code: ErrorCode.NotFound,
|
|
message: `Item ${handle.id} not found`,
|
|
})
|
|
}
|
|
}
|
|
|
|
// biome-ignore lint/suspicious/useIterableCallbackReturn: switch statement is exhaustive
|
|
const promises = handles.map((handle) => {
|
|
switch (handle.kind) {
|
|
case FileType.File:
|
|
return ctx.db
|
|
.patch(handle.id, {
|
|
deletedAt: Date.now(),
|
|
})
|
|
.then(() => handle)
|
|
case FileType.Directory:
|
|
return Directories.moveToTrashRecursive(ctx, handle).then(
|
|
() => handle,
|
|
)
|
|
}
|
|
})
|
|
|
|
const results = await Promise.allSettled(promises)
|
|
const errors = []
|
|
const okHandles: FileSystemHandle[] = []
|
|
for (const result of results) {
|
|
switch (result.status) {
|
|
case "fulfilled":
|
|
okHandles.push(result.value)
|
|
break
|
|
case "rejected":
|
|
errors.push(createErrorData(ErrorCode.Internal))
|
|
break
|
|
}
|
|
}
|
|
|
|
return {
|
|
deleted: okHandles,
|
|
errors,
|
|
}
|
|
},
|
|
})
|
|
|
|
export const fetchDirectoryContent = authenticatedQuery({
|
|
args: {
|
|
directoryId: v.optional(v.id("directories")),
|
|
trashed: v.boolean(),
|
|
},
|
|
handler: async (
|
|
ctx,
|
|
{ directoryId, trashed },
|
|
): Promise<FileSystemItem[]> => {
|
|
return await Directories.fetchContent(ctx, { directoryId, trashed })
|
|
},
|
|
})
|
|
|
|
export const permanentlyDeleteItems = authenticatedMutation({
|
|
args: {
|
|
handles: v.array(VFileSystemHandle),
|
|
},
|
|
handler: async (ctx, { handles }) => {
|
|
return await deleteItemsPermanently(ctx, { handles })
|
|
},
|
|
})
|
|
|
|
export const emptyTrash = authenticatedMutation({
|
|
handler: async (ctx) => {
|
|
return await emptyTrashImpl(ctx)
|
|
},
|
|
})
|
|
|
|
export const restoreItems = authenticatedMutation({
|
|
args: {
|
|
handles: v.array(VFileSystemHandle),
|
|
},
|
|
handler: async (ctx, { handles }) => {
|
|
return await restoreItemsImpl(ctx, { handles })
|
|
},
|
|
})
|
|
|
|
export const getStorageUrl = apiKeyAuthenticatedQuery({
|
|
args: {
|
|
storageId: v.id("_storage"),
|
|
},
|
|
handler: async (ctx, { storageId }) => {
|
|
return await ctx.storage.getUrl(storageId)
|
|
},
|
|
})
|
|
|
|
export const fetchFileUrl = authenticatedQuery({
|
|
args: {
|
|
fileId: v.id("files"),
|
|
},
|
|
handler: async (ctx, { fileId }) => {
|
|
return await fetchFileUrlImpl(ctx, { fileId })
|
|
},
|
|
})
|
|
|
|
export const openFile = authenticatedMutation({
|
|
args: {
|
|
fileId: v.id("files"),
|
|
},
|
|
handler: async (ctx, { fileId }) => {
|
|
return await FileSystem.openFile(ctx, { fileId })
|
|
},
|
|
})
|
|
|
|
export const saveFile = authenticatedMutation({
|
|
args: {
|
|
name: v.string(),
|
|
directoryId: v.id("directories"),
|
|
storageId: v.id("_storage"),
|
|
},
|
|
handler: async (ctx, { name, directoryId, storageId }) => {
|
|
return await FileSystem.saveFile(ctx, { name, directoryId, storageId })
|
|
},
|
|
})
|
|
|
|
export const fetchRecentFiles = authenticatedQuery({
|
|
args: {
|
|
limit: v.number(),
|
|
},
|
|
handler: async (ctx, { limit }) => {
|
|
return await FileSystem.fetchRecentFiles(ctx, { limit })
|
|
},
|
|
})
|