chore: update src/pages/api/repos/[owner]/[repo]/pulls/[number]/ai-review.ts
swadhinbiswas committed 8 months ago
07a9870
1 parent ad57825
commit 07a9870
1 file changed
+74 -5
Showing 1 changed file+74-5
▼src/pages/api/repos/[owner]/[repo]/pulls/[number]/ai-review.ts
+74-5
| @@ -1,14 +1,67 @@ | ||
1 | 1 | |
2 | 2 | import type { APIRoute } from "astro"; |
3 | -import { eq, and } from "drizzle-orm"; | |
3 | +import { eq, and, desc } from "drizzle-orm"; | |
4 | 4 | import type { NodePgDatabase } from "drizzle-orm/node-postgres"; |
5 | 5 | import { getDatabase, schema } from "@/db"; |
6 | 6 | import { getUserFromRequest } from "@/lib/auth"; |
7 | 7 | import { success } from "@/lib/api"; |
8 | 8 | import { withErrorHandler, Errors } from "@/lib/errors"; |
9 | 9 | import { triggerAIReview } from "@/lib/ai-review"; |
10 | +import type { AIProvider } from "@/lib/ai-review"; | |
10 | 11 | import { logger } from "@/lib/logger"; |
11 | 12 | import { parseAIConfigFromStorage } from "@/lib/ai-config"; |
13 | +import { canReadRepo } from "@/lib/permissions"; | |
14 | + | |
15 | +export const GET: APIRoute = withErrorHandler(async ({ params, locals }) => { | |
16 | + const { owner, repo: repoName, number } = params; | |
17 | + const user = locals.user; | |
18 | + const prNumber = Number.parseInt(number || "", 10); | |
19 | + if (!owner || !repoName || Number.isNaN(prNumber)) { | |
20 | + throw Errors.badRequest("Invalid repository or pull request"); | |
21 | + } | |
22 | + | |
23 | + const db = getDatabase() as NodePgDatabase<typeof schema>; | |
24 | + | |
25 | + const ownerUser = await db.query.users.findFirst({ | |
26 | + where: eq(schema.users.username, owner), | |
27 | + columns: { id: true }, | |
28 | + }); | |
29 | + if (!ownerUser) throw Errors.notFound("Repository owner not found"); | |
30 | + | |
31 | + const repository = await db.query.repositories.findFirst({ | |
32 | + where: and( | |
33 | + eq(schema.repositories.ownerId, ownerUser.id), | |
34 | + eq(schema.repositories.name, repoName) | |
35 | + ), | |
36 | + with: { owner: true }, | |
37 | + }); | |
38 | + if (!repository) throw Errors.notFound("Repository not found"); | |
39 | + | |
40 | + if (!(await canReadRepo(user?.id, repository, { isAdmin: user?.isAdmin }))) { | |
41 | + throw Errors.forbidden("Access denied"); | |
42 | + } | |
43 | + | |
44 | + const pr = await db.query.pullRequests.findFirst({ | |
45 | + where: and( | |
46 | + eq(schema.pullRequests.repositoryId, repository.id), | |
47 | + eq(schema.pullRequests.number, prNumber) | |
48 | + ), | |
49 | + }); | |
50 | + if (!pr) throw Errors.notFound("Pull request not found"); | |
51 | + | |
52 | + const review = await db.query.aiReviews.findFirst({ | |
53 | + where: eq(schema.aiReviews.pullRequestId, pr.id), | |
54 | + orderBy: [desc(schema.aiReviews.createdAt)], | |
55 | + }); | |
56 | + | |
57 | + if (!review) return success(null); | |
58 | + | |
59 | + const suggestions = await db.query.aiReviewSuggestions.findMany({ | |
60 | + where: eq(schema.aiReviewSuggestions.aiReviewId, review.id), | |
61 | + }); | |
62 | + | |
63 | + return success({ review, suggestions }); | |
64 | +}); | |
12 | 65 | |
13 | 66 | export const POST: APIRoute = withErrorHandler(async ({ request, params }) => { |
14 | 67 | const { owner, repo: repoName, number } = params; |
| @@ -54,8 +107,12 @@ export const POST: APIRoute = withErrorHandler(async ({ request, params }) => { | ||
54 | 107 | where: eq(schema.users.id, tokenPayload.userId), |
55 | 108 | }); |
56 | 109 | |
57 | - let aiConfig = { | |
58 | - provider: (process.env.AI_PROVIDER as any) || "openai", | |
110 | + let aiConfig: { | |
111 | + provider: AIProvider; | |
112 | + model: string; | |
113 | + apiKey?: string; | |
114 | + } = { | |
115 | + provider: ((process.env.AI_PROVIDER as AIProvider | undefined) || "openai"), | |
59 | 116 | model: "gpt-4-turbo", |
60 | 117 | apiKey: undefined, |
61 | 118 | }; |
| @@ -63,10 +120,22 @@ export const POST: APIRoute = withErrorHandler(async ({ request, params }) => { | ||
63 | 120 | if (currentUser?.aiConfig) { |
64 | 121 | try { |
65 | 122 | const userConfig = parseAIConfigFromStorage(currentUser.aiConfig); |
123 | + const provider: AIProvider = | |
124 | + userConfig.provider === "openai" || | |
125 | + userConfig.provider === "anthropic" || | |
126 | + userConfig.provider === "groq" || | |
127 | + userConfig.provider === "bytez" || | |
128 | + userConfig.provider === "local" | |
129 | + ? userConfig.provider | |
130 | + : "openai"; | |
131 | + const keyProvider = | |
132 | + provider === "openai" || provider === "groq" || provider === "bytez" | |
133 | + ? provider | |
134 | + : undefined; | |
66 | 135 | aiConfig = { |
67 | - provider: userConfig.provider || aiConfig.provider, | |
136 | + provider, | |
68 | 137 | model: userConfig.model || aiConfig.model, |
69 | - apiKey: userConfig.apiKeys?.[userConfig.provider], | |
138 | + apiKey: keyProvider ? userConfig.apiKeys?.[keyProvider] : undefined, | |
70 | 139 | }; |
71 | 140 | } catch (e) { |
72 | 141 | logger.error("Failed to parse user AI config", e); |
73 | 142 | |