Update package dependencies, enhance README for clarity, and implement new features in the admin panel and script detail pages. Added support for collections, improved script submission previews, and refactored comment handling in the script detail view.
This commit is contained in:
261
src/lib/api/collections.ts
Normal file
261
src/lib/api/collections.ts
Normal file
@ -0,0 +1,261 @@
|
||||
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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user