feat: add Saved Filters CRUD API
- Create lib/api/saved-filters.ts with GET, POST, PATCH, DELETE endpoints - All endpoints require authentication via requireAuth guard - Users can only access their own saved filters - Register savedFilterRoutes in lib/api/index.ts
This commit is contained in:
@@ -20,3 +20,4 @@ export { compareRoutes } from "./compare"
|
|||||||
export { playabilityRoutes } from "./playability"
|
export { playabilityRoutes } from "./playability"
|
||||||
export { steamReviewRoutes } from "./steam-reviews"
|
export { steamReviewRoutes } from "./steam-reviews"
|
||||||
export { communitySuggestionRoutes } from "./community-suggestions"
|
export { communitySuggestionRoutes } from "./community-suggestions"
|
||||||
|
export { savedFilterRoutes } from "./saved-filters"
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
import { Elysia, t } from "elysia"
|
||||||
|
import { db } from "@/lib/db/index"
|
||||||
|
import { savedFilters } from "@/lib/db/schema"
|
||||||
|
import { eq, and, desc } from "drizzle-orm"
|
||||||
|
import { requireAuth } from "@/lib/auth/guard"
|
||||||
|
|
||||||
|
export const savedFilterRoutes = new Elysia({ prefix: "/api/saved-filters" })
|
||||||
|
|
||||||
|
// Get user's saved filters
|
||||||
|
.get("/", async ({ request, set }) => {
|
||||||
|
const guard = await requireAuth(request.headers)
|
||||||
|
if (!guard.ok) {
|
||||||
|
set.status = guard.status
|
||||||
|
return { error: guard.error }
|
||||||
|
}
|
||||||
|
|
||||||
|
const filters = await db
|
||||||
|
.select()
|
||||||
|
.from(savedFilters)
|
||||||
|
.where(eq(savedFilters.userId, guard.user.id))
|
||||||
|
.orderBy(desc(savedFilters.updatedAt))
|
||||||
|
|
||||||
|
return filters
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a saved filter
|
||||||
|
.post(
|
||||||
|
"/",
|
||||||
|
async ({ body, request, set }) => {
|
||||||
|
const guard = await requireAuth(request.headers)
|
||||||
|
if (!guard.ok) {
|
||||||
|
set.status = guard.status
|
||||||
|
return { error: guard.error }
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, filters: filterData } = body
|
||||||
|
|
||||||
|
const [saved] = await db
|
||||||
|
.insert(savedFilters)
|
||||||
|
.values({
|
||||||
|
userId: guard.user.id,
|
||||||
|
name,
|
||||||
|
filters: filterData,
|
||||||
|
})
|
||||||
|
.returning()
|
||||||
|
|
||||||
|
return saved
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: t.Object({
|
||||||
|
name: t.String(),
|
||||||
|
filters: t.Record(t.String(), t.Any()),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update a saved filter
|
||||||
|
.patch(
|
||||||
|
"/:id",
|
||||||
|
async ({ params, body, request, set }) => {
|
||||||
|
const guard = await requireAuth(request.headers)
|
||||||
|
if (!guard.ok) {
|
||||||
|
set.status = guard.status
|
||||||
|
return { error: guard.error }
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, filters: filterData } = body
|
||||||
|
|
||||||
|
// Verify ownership
|
||||||
|
const [existing] = await db
|
||||||
|
.select()
|
||||||
|
.from(savedFilters)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(savedFilters.id, params.id),
|
||||||
|
eq(savedFilters.userId, guard.user.id),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
set.status = 404
|
||||||
|
return { error: "Saved filter not found" }
|
||||||
|
}
|
||||||
|
|
||||||
|
const [updated] = await db
|
||||||
|
.update(savedFilters)
|
||||||
|
.set({
|
||||||
|
...(name && { name }),
|
||||||
|
...(filterData && { filters: filterData }),
|
||||||
|
})
|
||||||
|
.where(eq(savedFilters.id, params.id))
|
||||||
|
.returning()
|
||||||
|
|
||||||
|
return updated
|
||||||
|
},
|
||||||
|
{
|
||||||
|
params: t.Object({ id: t.String() }),
|
||||||
|
body: t.Object({
|
||||||
|
name: t.Optional(t.String()),
|
||||||
|
filters: t.Optional(t.Record(t.String(), t.Any())),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Delete a saved filter
|
||||||
|
.delete(
|
||||||
|
"/:id",
|
||||||
|
async ({ params, request, set }) => {
|
||||||
|
const guard = await requireAuth(request.headers)
|
||||||
|
if (!guard.ok) {
|
||||||
|
set.status = guard.status
|
||||||
|
return { error: guard.error }
|
||||||
|
}
|
||||||
|
|
||||||
|
const [existing] = await db
|
||||||
|
.select()
|
||||||
|
.from(savedFilters)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(savedFilters.id, params.id),
|
||||||
|
eq(savedFilters.userId, guard.user.id),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
set.status = 404
|
||||||
|
return { error: "Saved filter not found" }
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.delete(savedFilters).where(eq(savedFilters.id, params.id))
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
params: t.Object({ id: t.String() }),
|
||||||
|
},
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user