mirror of
https://github.com/Tony0410/readlater.git
synced 2026-05-24 13:52:03 +08:00
New Features: - API key authentication for external access - Apple Shortcuts integration endpoint (/api/v1/add) - Full-text search across all articles - Folders for organizing articles - Highlights and notes on articles - Reading stats with streaks - Reading goals (daily/weekly/monthly) - Import from Pocket/Instapaper - RSS feed output - PWA support for mobile - Auto theme scheduling (day/night) - Settings page with all configuration API Endpoints: - /api/v1/add - Add articles via API key - /api/keys - Manage API keys - /api/search - Full-text search - /api/folders - Folder management - /api/highlights - Highlights/notes - /api/stats - Reading statistics - /api/goals - Reading goals - /api/import - Pocket/Instapaper import - /api/rss - RSS feed Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
95 lines
3.0 KiB
TypeScript
95 lines
3.0 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { db, schema } from "@/lib/db";
|
|
import { eq, asc } from "drizzle-orm";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
// GET /api/folders - List all folders
|
|
export async function GET() {
|
|
try {
|
|
const folders = await db
|
|
.select()
|
|
.from(schema.folders)
|
|
.orderBy(asc(schema.folders.sortOrder));
|
|
return NextResponse.json(folders);
|
|
} catch (error) {
|
|
console.error("Error listing folders:", error);
|
|
return NextResponse.json({ error: "Failed to list folders" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
// POST /api/folders - Create folder
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body = await request.json();
|
|
const { name, color, icon, parentId } = body;
|
|
|
|
if (!name) {
|
|
return NextResponse.json({ error: "Name is required" }, { status: 400 });
|
|
}
|
|
|
|
const id = uuidv4();
|
|
await db.insert(schema.folders).values({
|
|
id,
|
|
name,
|
|
color: color || "#3b82f6",
|
|
icon: icon || "folder",
|
|
parentId: parentId || null,
|
|
});
|
|
|
|
const folder = await db.select().from(schema.folders).where(eq(schema.folders.id, id)).limit(1);
|
|
return NextResponse.json(folder[0], { status: 201 });
|
|
} catch (error) {
|
|
console.error("Error creating folder:", error);
|
|
return NextResponse.json({ error: "Failed to create folder" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
// PATCH /api/folders - Update folder
|
|
export async function PATCH(request: NextRequest) {
|
|
try {
|
|
const body = await request.json();
|
|
const { id, name, color, icon, sortOrder } = body;
|
|
|
|
if (!id) {
|
|
return NextResponse.json({ error: "ID is required" }, { status: 400 });
|
|
}
|
|
|
|
const updates: Partial<schema.Folder> = {};
|
|
if (name) updates.name = name;
|
|
if (color) updates.color = color;
|
|
if (icon) updates.icon = icon;
|
|
if (sortOrder !== undefined) updates.sortOrder = sortOrder;
|
|
|
|
await db.update(schema.folders).set(updates).where(eq(schema.folders.id, id));
|
|
|
|
const folder = await db.select().from(schema.folders).where(eq(schema.folders.id, id)).limit(1);
|
|
return NextResponse.json(folder[0]);
|
|
} catch (error) {
|
|
console.error("Error updating folder:", error);
|
|
return NextResponse.json({ error: "Failed to update folder" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
// DELETE /api/folders?id=...
|
|
export async function DELETE(request: NextRequest) {
|
|
try {
|
|
const { searchParams } = new URL(request.url);
|
|
const id = searchParams.get("id");
|
|
|
|
if (!id) {
|
|
return NextResponse.json({ error: "ID is required" }, { status: 400 });
|
|
}
|
|
|
|
// Remove folder reference from articles
|
|
await db.update(schema.articles).set({ folderId: null }).where(eq(schema.articles.folderId, id));
|
|
|
|
// Delete folder
|
|
await db.delete(schema.folders).where(eq(schema.folders.id, id));
|
|
|
|
return NextResponse.json({ success: true });
|
|
} catch (error) {
|
|
console.error("Error deleting folder:", error);
|
|
return NextResponse.json({ error: "Failed to delete folder" }, { status: 500 });
|
|
}
|
|
}
|