feat: record abs path of dirs
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
|
import type { Id } from "@convex/_generated/dataModel"
|
||||||
import { v } from "convex/values"
|
import { v } from "convex/values"
|
||||||
import type { Id } from "./_generated/dataModel"
|
|
||||||
import { authenticatedMutation, authenticatedQuery } from "./functions"
|
import { authenticatedMutation, authenticatedQuery } from "./functions"
|
||||||
import type { DirectoryItem } from "./model/directories"
|
import type { DirectoryItem } from "./model/directories"
|
||||||
import * as Directories from "./model/directories"
|
import * as Directories from "./model/directories"
|
||||||
@@ -18,8 +18,9 @@ export const fetchFiles = authenticatedQuery({
|
|||||||
handler: async (ctx, { directoryId }) => {
|
handler: async (ctx, { directoryId }) => {
|
||||||
return await ctx.db
|
return await ctx.db
|
||||||
.query("files")
|
.query("files")
|
||||||
.withIndex("byDirectoryId", (q) => q.eq("directoryId", directoryId))
|
.withIndex("byDirectoryId", (q) =>
|
||||||
.filter((q) => q.eq(q.field("userId"), ctx.user._id))
|
q.eq("userId", ctx.user._id).eq("directoryId", directoryId),
|
||||||
|
)
|
||||||
.collect()
|
.collect()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -29,7 +30,7 @@ export const fetchDirectoryContent = authenticatedQuery({
|
|||||||
directoryId: v.optional(v.id("directories")),
|
directoryId: v.optional(v.id("directories")),
|
||||||
},
|
},
|
||||||
handler: async (ctx, { directoryId }): Promise<DirectoryItem[]> => {
|
handler: async (ctx, { directoryId }): Promise<DirectoryItem[]> => {
|
||||||
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, {
|
return await Directories.create(ctx, {
|
||||||
name,
|
name,
|
||||||
parentId: directoryId,
|
parentId: directoryId,
|
||||||
userId: ctx.user._id,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -77,7 +77,6 @@ export const moveToTrash = authenticatedMutation({
|
|||||||
itemId: v.union(v.id("files"), v.id("directories")),
|
itemId: v.union(v.id("files"), v.id("directories")),
|
||||||
},
|
},
|
||||||
handler: async (ctx, { itemId, kind }) => {
|
handler: async (ctx, { itemId, kind }) => {
|
||||||
// Verify ownership before allowing deletion
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case "file": {
|
case "file": {
|
||||||
const file = await ctx.db.get(itemId as Id<"files">)
|
const file = await ctx.db.get(itemId as Id<"files">)
|
||||||
@@ -97,7 +96,6 @@ export const moveToTrash = authenticatedMutation({
|
|||||||
await Directories.moveToTrashRecursive(
|
await Directories.moveToTrashRecursive(
|
||||||
ctx,
|
ctx,
|
||||||
itemId as Id<"directories">,
|
itemId as Id<"directories">,
|
||||||
ctx.user._id,
|
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
import type { Doc, Id } from "@convex/_generated/dataModel"
|
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"
|
import * as Err from "./error"
|
||||||
|
|
||||||
type Directory = {
|
type Directory = {
|
||||||
@@ -16,23 +19,27 @@ export type DirectoryItem = Directory | File
|
|||||||
export type DirectoryItemKind = DirectoryItem["kind"]
|
export type DirectoryItemKind = DirectoryItem["kind"]
|
||||||
|
|
||||||
export async function fetchContent(
|
export async function fetchContent(
|
||||||
ctx: QueryCtx,
|
ctx: AuthenticatedQueryCtx,
|
||||||
directoryId?: Id<"directories">,
|
directoryId?: Id<"directories">,
|
||||||
userId?: Id<"users">,
|
|
||||||
): Promise<DirectoryItem[]> {
|
): Promise<DirectoryItem[]> {
|
||||||
const [files, directories] = await Promise.all([
|
const [files, directories] = await Promise.all([
|
||||||
ctx.db
|
ctx.db
|
||||||
.query("files")
|
.query("files")
|
||||||
.withIndex("byDirectoryId", (q) =>
|
.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(),
|
.collect(),
|
||||||
ctx.db
|
ctx.db
|
||||||
.query("directories")
|
.query("directories")
|
||||||
.withIndex("byParentId", (q) => q.eq("parentId", directoryId))
|
.withIndex("byParentId", (q) =>
|
||||||
.filter((q) => q.eq(q.field("deletedAt"), undefined))
|
q
|
||||||
.filter((q) => userId ? q.eq(q.field("userId"), userId) : q.neq(q.field("userId"), null))
|
.eq("userId", ctx.user._id)
|
||||||
|
.eq("parentId", directoryId)
|
||||||
|
.eq("deletedAt", undefined),
|
||||||
|
)
|
||||||
.collect(),
|
.collect(),
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -48,16 +55,16 @@ export async function fetchContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function create(
|
export async function create(
|
||||||
ctx: MutationCtx,
|
ctx: AuthenticatedMutationCtx,
|
||||||
{ name, parentId, userId }: { name: string; parentId?: Id<"directories">; userId: Id<"users"> },
|
{ name, parentId }: { name: string; parentId?: Id<"directories"> },
|
||||||
): Promise<Id<"directories">> {
|
): Promise<Id<"directories">> {
|
||||||
// Check if parent directory exists and belongs to user
|
let parentDir: Doc<"directories"> | null = null
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
const parentDir = await ctx.db.get(parentId)
|
parentDir = await ctx.db.get(parentId)
|
||||||
if (!parentDir || parentDir.userId !== userId) {
|
if (!parentDir) {
|
||||||
throw Err.create(
|
throw Err.create(
|
||||||
Err.Code.DirectoryExists,
|
Err.Code.DirectoryNotFound,
|
||||||
"Parent directory not found or access denied",
|
`Parent directory ${parentId} not found`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,9 +72,12 @@ export async function create(
|
|||||||
const existing = await ctx.db
|
const existing = await ctx.db
|
||||||
.query("directories")
|
.query("directories")
|
||||||
.withIndex("uniqueDirectoryInDirectory", (q) =>
|
.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()
|
.first()
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
@@ -81,16 +91,16 @@ export async function create(
|
|||||||
return await ctx.db.insert("directories", {
|
return await ctx.db.insert("directories", {
|
||||||
name,
|
name,
|
||||||
parentId,
|
parentId,
|
||||||
userId,
|
userId: ctx.user._id,
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
|
path: parentDir ? `${parentDir.path}/${name}` : "/",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function moveToTrashRecursive(
|
export async function moveToTrashRecursive(
|
||||||
ctx: MutationCtx,
|
ctx: AuthenticatedMutationCtx,
|
||||||
directoryId: Id<"directories">,
|
directoryId: Id<"directories">,
|
||||||
userId: Id<"users">,
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const now = new Date().toISOString()
|
const now = new Date().toISOString()
|
||||||
|
|
||||||
@@ -107,10 +117,10 @@ export async function moveToTrashRecursive(
|
|||||||
.query("files")
|
.query("files")
|
||||||
.withIndex("byDirectoryId", (q) =>
|
.withIndex("byDirectoryId", (q) =>
|
||||||
q
|
q
|
||||||
|
.eq("userId", ctx.user._id)
|
||||||
.eq("directoryId", currentDirectoryId)
|
.eq("directoryId", currentDirectoryId)
|
||||||
.eq("deletedAt", undefined),
|
.eq("deletedAt", undefined),
|
||||||
)
|
)
|
||||||
.filter((q) => q.eq(q.field("userId"), userId))
|
|
||||||
.collect()
|
.collect()
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
@@ -120,9 +130,11 @@ export async function moveToTrashRecursive(
|
|||||||
const subdirectories = await ctx.db
|
const subdirectories = await ctx.db
|
||||||
.query("directories")
|
.query("directories")
|
||||||
.withIndex("byParentId", (q) =>
|
.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()
|
.collect()
|
||||||
|
|
||||||
for (const subdirectory of subdirectories) {
|
for (const subdirectory of subdirectories) {
|
||||||
|
@@ -2,6 +2,7 @@ import { ConvexError } from "convex/values"
|
|||||||
|
|
||||||
export enum Code {
|
export enum Code {
|
||||||
DirectoryExists = "DirectoryExists",
|
DirectoryExists = "DirectoryExists",
|
||||||
|
DirectoryNotFound = "DirectoryNotFound",
|
||||||
FileExists = "FileExists",
|
FileExists = "FileExists",
|
||||||
Internal = "Internal",
|
Internal = "Internal",
|
||||||
Unauthenticated = "Unauthenticated",
|
Unauthenticated = "Unauthenticated",
|
||||||
|
@@ -16,12 +16,18 @@ const schema = defineSchema({
|
|||||||
updatedAt: v.string(),
|
updatedAt: v.string(),
|
||||||
deletedAt: v.optional(v.string()),
|
deletedAt: v.optional(v.string()),
|
||||||
})
|
})
|
||||||
.index("byDirectoryId", ["directoryId", "deletedAt"])
|
.index("byDirectoryId", ["userId", "directoryId", "deletedAt"])
|
||||||
.index("byUserId", ["userId", "deletedAt"])
|
.index("byUserId", ["userId", "deletedAt"])
|
||||||
.index("byDeletedAt", ["deletedAt"])
|
.index("byDeletedAt", ["deletedAt"])
|
||||||
.index("uniqueFileInDirectory", ["directoryId", "name", "deletedAt"]),
|
.index("uniqueFileInDirectory", [
|
||||||
|
"userId",
|
||||||
|
"directoryId",
|
||||||
|
"name",
|
||||||
|
"deletedAt",
|
||||||
|
]),
|
||||||
directories: defineTable({
|
directories: defineTable({
|
||||||
name: v.string(),
|
name: v.string(),
|
||||||
|
path: v.string(),
|
||||||
userId: v.id("users"),
|
userId: v.id("users"),
|
||||||
parentId: v.optional(v.id("directories")),
|
parentId: v.optional(v.id("directories")),
|
||||||
createdAt: v.string(),
|
createdAt: v.string(),
|
||||||
@@ -29,8 +35,14 @@ const schema = defineSchema({
|
|||||||
deletedAt: v.optional(v.string()),
|
deletedAt: v.optional(v.string()),
|
||||||
})
|
})
|
||||||
.index("byUserId", ["userId", "deletedAt"])
|
.index("byUserId", ["userId", "deletedAt"])
|
||||||
.index("byParentId", ["parentId", "deletedAt"])
|
.index("byParentId", ["userId", "parentId", "deletedAt"])
|
||||||
.index("uniqueDirectoryInDirectory", ["parentId", "name", "deletedAt"]),
|
.index("uniqueDirectoryInDirectory", [
|
||||||
|
"userId",
|
||||||
|
"parentId",
|
||||||
|
"name",
|
||||||
|
"deletedAt",
|
||||||
|
])
|
||||||
|
.index("byPath", ["path", "deletedAt"]),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default schema
|
export default schema
|
||||||
|
Reference in New Issue
Block a user