Files
scriptshare-cursor/src/lib/api/collections.ts

262 lines
7.3 KiB
TypeScript

import { db } from '@/lib/db';
import { scriptCollections, collectionScripts, scripts } from '@/lib/db/schema';
import { eq, and, desc } from 'drizzle-orm';
import { generateId, ApiError } from './index';
export interface CreateCollectionData {
name: string;
description?: string;
authorId: string;
isPublic?: boolean;
}
export interface UpdateCollectionData {
name?: string;
description?: string;
isPublic?: boolean;
}
// Create a new collection
export async function createCollection(data: CreateCollectionData) {
try {
const collectionId = generateId();
const now = new Date();
const [collection] = await db.insert(scriptCollections).values({
id: collectionId,
name: data.name,
description: data.description,
authorId: data.authorId,
isPublic: data.isPublic ?? true,
createdAt: now,
updatedAt: now,
}).returning();
return collection;
} catch (error) {
throw new ApiError(`Failed to create collection: ${error}`, 500);
}
}
// Get collection by ID
export async function getCollectionById(id: string) {
try {
const collection = await db.query.scriptCollections.findFirst({
where: eq(scriptCollections.id, id),
with: {
author: {
columns: {
id: true,
username: true,
displayName: true,
avatarUrl: true,
},
},
scripts: {
with: {
script: {
with: {
author: {
columns: {
id: true,
username: true,
displayName: true,
avatarUrl: true,
},
},
},
},
},
orderBy: desc(collectionScripts.addedAt),
},
},
});
if (!collection) {
throw new ApiError('Collection not found', 404);
}
return collection;
} catch (error) {
if (error instanceof ApiError) throw error;
throw new ApiError(`Failed to get collection: ${error}`, 500);
}
}
// Get collections by user
export async function getUserCollections(userId: string) {
try {
const collections = await db.query.scriptCollections.findMany({
where: eq(scriptCollections.authorId, userId),
with: {
scripts: {
with: {
script: true,
},
},
},
orderBy: desc(scriptCollections.createdAt),
});
return collections;
} catch (error) {
throw new ApiError(`Failed to get user collections: ${error}`, 500);
}
}
// Get public collections
export async function getPublicCollections(limit: number = 20, offset: number = 0) {
try {
const collections = await db.query.scriptCollections.findMany({
where: eq(scriptCollections.isPublic, true),
with: {
author: {
columns: {
id: true,
username: true,
displayName: true,
avatarUrl: true,
},
},
scripts: {
with: {
script: true,
},
limit: 5, // Preview of scripts in collection
},
},
orderBy: desc(scriptCollections.createdAt),
limit,
offset,
});
return collections;
} catch (error) {
throw new ApiError(`Failed to get public collections: ${error}`, 500);
}
}
// Update collection
export async function updateCollection(id: string, data: UpdateCollectionData, userId: string) {
try {
// Check if user owns the collection
const collection = await getCollectionById(id);
if (collection.authorId !== userId) {
throw new ApiError('Unauthorized to update this collection', 403);
}
const updateData = {
...data,
updatedAt: new Date(),
};
const [updatedCollection] = await db
.update(scriptCollections)
.set(updateData)
.where(eq(scriptCollections.id, id))
.returning();
return updatedCollection;
} catch (error) {
if (error instanceof ApiError) throw error;
throw new ApiError(`Failed to update collection: ${error}`, 500);
}
}
// Delete collection
export async function deleteCollection(id: string, userId: string) {
try {
const collection = await getCollectionById(id);
if (collection.authorId !== userId) {
throw new ApiError('Unauthorized to delete this collection', 403);
}
// Delete all scripts in collection first
await db.delete(collectionScripts).where(eq(collectionScripts.collectionId, id));
// Delete the collection
await db.delete(scriptCollections).where(eq(scriptCollections.id, id));
return { success: true };
} catch (error) {
if (error instanceof ApiError) throw error;
throw new ApiError(`Failed to delete collection: ${error}`, 500);
}
}
// Add script to collection
export async function addScriptToCollection(collectionId: string, scriptId: string, userId: string) {
try {
// Check if user owns the collection
const collection = await getCollectionById(collectionId);
if (collection.authorId !== userId) {
throw new ApiError('Unauthorized to modify this collection', 403);
}
// Check if script is already in collection
const existing = await db.query.collectionScripts.findFirst({
where: and(
eq(collectionScripts.collectionId, collectionId),
eq(collectionScripts.scriptId, scriptId)
),
});
if (existing) {
throw new ApiError('Script is already in this collection', 400);
}
const [collectionScript] = await db.insert(collectionScripts).values({
id: generateId(),
collectionId,
scriptId,
addedAt: new Date(),
}).returning();
return collectionScript;
} catch (error) {
if (error instanceof ApiError) throw error;
throw new ApiError(`Failed to add script to collection: ${error}`, 500);
}
}
// Remove script from collection
export async function removeScriptFromCollection(collectionId: string, scriptId: string, userId: string) {
try {
// Check if user owns the collection
const collection = await getCollectionById(collectionId);
if (collection.authorId !== userId) {
throw new ApiError('Unauthorized to modify this collection', 403);
}
await db
.delete(collectionScripts)
.where(
and(
eq(collectionScripts.collectionId, collectionId),
eq(collectionScripts.scriptId, scriptId)
)
);
return { success: true };
} catch (error) {
if (error instanceof ApiError) throw error;
throw new ApiError(`Failed to remove script from collection: ${error}`, 500);
}
}
// Check if script is in collection
export async function isScriptInCollection(collectionId: string, scriptId: string) {
try {
const collectionScript = await db.query.collectionScripts.findFirst({
where: and(
eq(collectionScripts.collectionId, collectionId),
eq(collectionScripts.scriptId, scriptId)
),
});
return !!collectionScript;
} catch (error) {
throw new ApiError(`Failed to check if script is in collection: ${error}`, 500);
}
}