From 7cad95307b90c69af8287437a1a4d4219cd91590 Mon Sep 17 00:00:00 2001 From: kenneth Date: Tue, 16 Sep 2025 22:36:26 +0000 Subject: [PATCH] feat: record abs path of dirs --- convex/files.ts | 12 ++++---- convex/model/directories.ts | 58 ++++++++++++++++++++++--------------- convex/model/error.ts | 1 + convex/schema.ts | 20 ++++++++++--- 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/convex/files.ts b/convex/files.ts index ffac908..c371940 100644 --- a/convex/files.ts +++ b/convex/files.ts @@ -1,5 +1,5 @@ +import type { Id } from "@convex/_generated/dataModel" import { v } from "convex/values" -import type { Id } from "./_generated/dataModel" import { authenticatedMutation, authenticatedQuery } from "./functions" import type { DirectoryItem } from "./model/directories" import * as Directories from "./model/directories" @@ -18,8 +18,9 @@ export const fetchFiles = authenticatedQuery({ handler: async (ctx, { directoryId }) => { return await ctx.db .query("files") - .withIndex("byDirectoryId", (q) => q.eq("directoryId", directoryId)) - .filter((q) => q.eq(q.field("userId"), ctx.user._id)) + .withIndex("byDirectoryId", (q) => + q.eq("userId", ctx.user._id).eq("directoryId", directoryId), + ) .collect() }, }) @@ -29,7 +30,7 @@ export const fetchDirectoryContent = authenticatedQuery({ directoryId: v.optional(v.id("directories")), }, handler: async (ctx, { directoryId }): Promise => { - return await Directories.fetchContent(ctx, directoryId, ctx.user._id) + return await Directories.fetchContent(ctx, directoryId) }, }) @@ -42,7 +43,6 @@ export const createDirectory = authenticatedMutation({ return await Directories.create(ctx, { name, parentId: directoryId, - userId: ctx.user._id, }) }, }) @@ -77,7 +77,6 @@ export const moveToTrash = authenticatedMutation({ itemId: v.union(v.id("files"), v.id("directories")), }, handler: async (ctx, { itemId, kind }) => { - // Verify ownership before allowing deletion switch (kind) { case "file": { const file = await ctx.db.get(itemId as Id<"files">) @@ -97,7 +96,6 @@ export const moveToTrash = authenticatedMutation({ await Directories.moveToTrashRecursive( ctx, itemId as Id<"directories">, - ctx.user._id, ) break } diff --git a/convex/model/directories.ts b/convex/model/directories.ts index fa1ced0..91c0da4 100644 --- a/convex/model/directories.ts +++ b/convex/model/directories.ts @@ -1,5 +1,8 @@ import type { Doc, Id } from "@convex/_generated/dataModel" -import type { MutationCtx, QueryCtx } from "@convex/_generated/server" +import type { + AuthenticatedMutationCtx, + AuthenticatedQueryCtx, +} from "../functions" import * as Err from "./error" type Directory = { @@ -16,23 +19,27 @@ export type DirectoryItem = Directory | File export type DirectoryItemKind = DirectoryItem["kind"] export async function fetchContent( - ctx: QueryCtx, + ctx: AuthenticatedQueryCtx, directoryId?: Id<"directories">, - userId?: Id<"users">, ): Promise { const [files, directories] = await Promise.all([ ctx.db .query("files") .withIndex("byDirectoryId", (q) => - q.eq("directoryId", directoryId).eq("deletedAt", undefined), + q + .eq("userId", ctx.user._id) + .eq("directoryId", directoryId) + .eq("deletedAt", undefined), ) - .filter((q) => userId ? q.eq(q.field("userId"), userId) : q.neq(q.field("userId"), null)) .collect(), ctx.db .query("directories") - .withIndex("byParentId", (q) => q.eq("parentId", directoryId)) - .filter((q) => q.eq(q.field("deletedAt"), undefined)) - .filter((q) => userId ? q.eq(q.field("userId"), userId) : q.neq(q.field("userId"), null)) + .withIndex("byParentId", (q) => + q + .eq("userId", ctx.user._id) + .eq("parentId", directoryId) + .eq("deletedAt", undefined), + ) .collect(), ]) @@ -48,16 +55,16 @@ export async function fetchContent( } export async function create( - ctx: MutationCtx, - { name, parentId, userId }: { name: string; parentId?: Id<"directories">; userId: Id<"users"> }, + ctx: AuthenticatedMutationCtx, + { name, parentId }: { name: string; parentId?: Id<"directories"> }, ): Promise> { - // Check if parent directory exists and belongs to user + let parentDir: Doc<"directories"> | null = null if (parentId) { - const parentDir = await ctx.db.get(parentId) - if (!parentDir || parentDir.userId !== userId) { + parentDir = await ctx.db.get(parentId) + if (!parentDir) { throw Err.create( - Err.Code.DirectoryExists, - "Parent directory not found or access denied", + Err.Code.DirectoryNotFound, + `Parent directory ${parentId} not found`, ) } } @@ -65,9 +72,12 @@ export async function create( const existing = await ctx.db .query("directories") .withIndex("uniqueDirectoryInDirectory", (q) => - q.eq("parentId", parentId).eq("name", name), + q + .eq("userId", ctx.user._id) + .eq("parentId", parentId) + .eq("name", name) + .eq("deletedAt", undefined), ) - .filter((q) => q.eq(q.field("userId"), userId)) .first() if (existing) { @@ -81,16 +91,16 @@ export async function create( return await ctx.db.insert("directories", { name, parentId, - userId, + userId: ctx.user._id, createdAt: now, updatedAt: now, + path: parentDir ? `${parentDir.path}/${name}` : "/", }) } export async function moveToTrashRecursive( - ctx: MutationCtx, + ctx: AuthenticatedMutationCtx, directoryId: Id<"directories">, - userId: Id<"users">, ): Promise { const now = new Date().toISOString() @@ -107,10 +117,10 @@ export async function moveToTrashRecursive( .query("files") .withIndex("byDirectoryId", (q) => q + .eq("userId", ctx.user._id) .eq("directoryId", currentDirectoryId) .eq("deletedAt", undefined), ) - .filter((q) => q.eq(q.field("userId"), userId)) .collect() for (const file of files) { @@ -120,9 +130,11 @@ export async function moveToTrashRecursive( const subdirectories = await ctx.db .query("directories") .withIndex("byParentId", (q) => - q.eq("parentId", currentDirectoryId).eq("deletedAt", undefined), + q + .eq("userId", ctx.user._id) + .eq("parentId", currentDirectoryId) + .eq("deletedAt", undefined), ) - .filter((q) => q.eq(q.field("userId"), userId)) .collect() for (const subdirectory of subdirectories) { diff --git a/convex/model/error.ts b/convex/model/error.ts index 76a1673..117fb7d 100644 --- a/convex/model/error.ts +++ b/convex/model/error.ts @@ -2,6 +2,7 @@ import { ConvexError } from "convex/values" export enum Code { DirectoryExists = "DirectoryExists", + DirectoryNotFound = "DirectoryNotFound", FileExists = "FileExists", Internal = "Internal", Unauthenticated = "Unauthenticated", diff --git a/convex/schema.ts b/convex/schema.ts index 835e592..6bb1424 100644 --- a/convex/schema.ts +++ b/convex/schema.ts @@ -16,12 +16,18 @@ const schema = defineSchema({ updatedAt: v.string(), deletedAt: v.optional(v.string()), }) - .index("byDirectoryId", ["directoryId", "deletedAt"]) + .index("byDirectoryId", ["userId", "directoryId", "deletedAt"]) .index("byUserId", ["userId", "deletedAt"]) .index("byDeletedAt", ["deletedAt"]) - .index("uniqueFileInDirectory", ["directoryId", "name", "deletedAt"]), + .index("uniqueFileInDirectory", [ + "userId", + "directoryId", + "name", + "deletedAt", + ]), directories: defineTable({ name: v.string(), + path: v.string(), userId: v.id("users"), parentId: v.optional(v.id("directories")), createdAt: v.string(), @@ -29,8 +35,14 @@ const schema = defineSchema({ deletedAt: v.optional(v.string()), }) .index("byUserId", ["userId", "deletedAt"]) - .index("byParentId", ["parentId", "deletedAt"]) - .index("uniqueDirectoryInDirectory", ["parentId", "name", "deletedAt"]), + .index("byParentId", ["userId", "parentId", "deletedAt"]) + .index("uniqueDirectoryInDirectory", [ + "userId", + "parentId", + "name", + "deletedAt", + ]) + .index("byPath", ["path", "deletedAt"]), }) export default schema