feat(db): migration and database setup
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { HTTPException } from "hono/http-exception";
|
||||
|
||||
import { env } from "@/config";
|
||||
|
||||
export const withCrawlerAuth: MiddlewareHandler = async (c, next) => {
|
||||
const token = c.req.header("Authorization");
|
||||
|
||||
if (!token) {
|
||||
throw new HTTPException(401, { message: "Authorization header required" });
|
||||
}
|
||||
|
||||
if (token !== env("BASANGO_CRAWLER_KEY")) {
|
||||
throw new HTTPException(403, { message: "Invalid token" });
|
||||
}
|
||||
|
||||
await next();
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
import { db } from "@basango/db/client";
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
|
||||
export const withDatabase: MiddlewareHandler = async (c, next) => {
|
||||
c.set("db", db);
|
||||
|
||||
await next();
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
|
||||
import type { Scope } from "@/utils/scopes";
|
||||
|
||||
export const withRequiredScope = (...requiredScopes: Scope[]): MiddlewareHandler => {
|
||||
return async (c, next) => {
|
||||
const scopes = c.get("scopes") as Scope[] | undefined;
|
||||
|
||||
if (!scopes) {
|
||||
return c.json(
|
||||
{
|
||||
description: "No scopes found for the current user. Authentication is required.",
|
||||
error: "Unauthorized",
|
||||
},
|
||||
401,
|
||||
);
|
||||
}
|
||||
|
||||
// Check if user has at least one of the required scopes
|
||||
const hasRequiredScope = requiredScopes.some((requiredScope) => scopes.includes(requiredScope));
|
||||
|
||||
if (!hasRequiredScope) {
|
||||
return c.json(
|
||||
{
|
||||
description: `Insufficient permissions. Required scopes: ${requiredScopes.join(
|
||||
", ",
|
||||
)}. Your scopes: ${scopes.join(", ")}`,
|
||||
error: "Forbidden",
|
||||
},
|
||||
403,
|
||||
);
|
||||
}
|
||||
|
||||
await next();
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
import { createArticle } from "@basango/db/queries";
|
||||
import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
|
||||
|
||||
import { withCrawlerAuth } from "@/rest/middlewares/crawler";
|
||||
import type { Context } from "@/rest/types";
|
||||
import { createArticleResponseSchema, createArticleSchema } from "@/schemas/articles";
|
||||
import { validateResponse } from "@/utils/response";
|
||||
|
||||
const app = new OpenAPIHono<Context>();
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
description: "Store a new crawled article in the database.",
|
||||
method: "post",
|
||||
middleware: [withCrawlerAuth],
|
||||
operationId: "CreateArticle",
|
||||
path: "/",
|
||||
request: {
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: createArticleSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: createArticleResponseSchema,
|
||||
},
|
||||
},
|
||||
description: "Article created",
|
||||
},
|
||||
},
|
||||
summary: "Create Article",
|
||||
tags: ["Articles"],
|
||||
"x-speakeasy-name-override": "create",
|
||||
}),
|
||||
async (c) => {
|
||||
const db = c.get("db");
|
||||
const body = c.req.valid("json");
|
||||
const result = await createArticle(db, { ...body });
|
||||
|
||||
return c.json(
|
||||
validateResponse(result, createArticleResponseSchema) as { id: string; sourceId: string },
|
||||
201,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const articlesRouter = app;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||
|
||||
import { articlesRouter } from "@/rest/routers/articles";
|
||||
|
||||
const routers = new OpenAPIHono();
|
||||
|
||||
routers.route("/articles", articlesRouter);
|
||||
|
||||
export { routers };
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { Database } from "@basango/db/client";
|
||||
|
||||
export type Context = {
|
||||
Variables: {
|
||||
db: Database;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user