Add user authentication and dynamic feature/category inputs
Implement Keycloak authentication, protected routes, and add combobox and autocomplete components for tool categories and features. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 776963d0-f75d-42e2-a57b-cc36bdff8495 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 0b145113-c016-4f54-b000-13bd3b0ba8f0 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0683fb79-a27c-485c-9333-5f4b288c4567/776963d0-f75d-42e2-a57b-cc36bdff8495/z4uWN6A Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Router, type IRouter } from "express";
|
||||
import { eq, ilike, desc, sql, avg, count } from "drizzle-orm";
|
||||
import { eq, ilike, desc, sql } from "drizzle-orm";
|
||||
import { db, toolsTable, ratingsTable } from "@workspace/db";
|
||||
import {
|
||||
ListToolsQueryParams,
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
UpdateToolBody,
|
||||
DeleteToolParams,
|
||||
} from "@workspace/api-zod";
|
||||
import { requireAuth } from "../middleware/auth";
|
||||
|
||||
const router: IRouter = Router();
|
||||
|
||||
@@ -71,7 +72,7 @@ router.get("/tools", async (req, res): Promise<void> => {
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
router.post("/tools", async (req, res): Promise<void> => {
|
||||
router.post("/tools", requireAuth, async (req, res): Promise<void> => {
|
||||
const parsed = CreateToolBody.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ error: parsed.error.message });
|
||||
@@ -111,7 +112,7 @@ router.get("/tools/:id", async (req, res): Promise<void> => {
|
||||
res.json(buildToolWithStats(tool, ratings));
|
||||
});
|
||||
|
||||
router.patch("/tools/:id", async (req, res): Promise<void> => {
|
||||
router.patch("/tools/:id", requireAuth, async (req, res): Promise<void> => {
|
||||
const params = UpdateToolParams.safeParse(req.params);
|
||||
if (!params.success) {
|
||||
res.status(400).json({ error: params.error.message });
|
||||
@@ -146,7 +147,7 @@ router.patch("/tools/:id", async (req, res): Promise<void> => {
|
||||
res.json(tool);
|
||||
});
|
||||
|
||||
router.delete("/tools/:id", async (req, res): Promise<void> => {
|
||||
router.delete("/tools/:id", requireAuth, async (req, res): Promise<void> => {
|
||||
const params = DeleteToolParams.safeParse(req.params);
|
||||
if (!params.success) {
|
||||
res.status(400).json({ error: params.error.message });
|
||||
@@ -170,4 +171,15 @@ router.get("/categories", async (_req, res): Promise<void> => {
|
||||
res.json(rows.map((r) => r.category));
|
||||
});
|
||||
|
||||
router.get("/features/all", async (_req, res): Promise<void> => {
|
||||
const tools = await db.select({ features: toolsTable.features }).from(toolsTable);
|
||||
const featureSet = new Set<string>();
|
||||
for (const t of tools) {
|
||||
for (const f of t.features ?? []) {
|
||||
if (f && f.trim()) featureSet.add(f.trim());
|
||||
}
|
||||
}
|
||||
res.json([...featureSet].sort());
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user