-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api): update API route to new app router handlers
- Loading branch information
Showing
7 changed files
with
673 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import { NextRequest, NextResponse } from "next/server"; | ||
|
||
async function turnstile(token: string, ip: string | null) { | ||
const formData = new URLSearchParams(); | ||
|
||
formData.append("secret", process.env.TURNSTILE_KEY as string); | ||
formData.append("response", token); | ||
|
||
if (ip) { | ||
formData.append("remoteip", ip); | ||
} | ||
|
||
const url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"; | ||
|
||
const result = await fetch(url, { | ||
body: formData, | ||
method: "POST", | ||
}); | ||
|
||
return (await result.json()) as | ||
| { | ||
success: true; | ||
challenge_ts: string; | ||
hostname: string; | ||
"error-codes": string[]; | ||
action: string; | ||
cdata: string; | ||
} | ||
| { | ||
success: false; | ||
"error-codes": [string, ...string[]]; | ||
}; | ||
} | ||
|
||
export async function POST(request: NextRequest) { | ||
try { | ||
const body = await request.json(); | ||
|
||
const forwardedFor = request.headers.get("x-forwarded-for"); | ||
const ip = | ||
forwardedFor?.split(",")[0] ?? | ||
request.headers.get("x-real-ip") ?? | ||
request.headers.get("cf-connecting-ip") ?? | ||
null; | ||
|
||
const outcome = await turnstile(body.turnstile, ip); | ||
|
||
if (!outcome.success) { | ||
return new NextResponse(null, { status: 400 }); | ||
} | ||
|
||
const linearResponse = await fetch("https://api.linear.app/graphql", { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
Authorization: `${process.env.LINEAR_API_KEY}`, | ||
}, | ||
body: JSON.stringify({ | ||
query: `mutation IssueCreate{ | ||
issueCreate( | ||
input: { | ||
title: "${body.short}", | ||
description: "**Reported by:** ${body.user.discord_name} (${body.user.discord_id})\\n\\n${body.long}\\n\\nIP: ${ip}", | ||
teamId: "${process.env.LINEAR_TEAM_ID}", | ||
labelIds: ["${process.env.LINEAR_BUG_LABEL}"] | ||
} | ||
) { | ||
success | ||
issue { | ||
id | ||
identifier | ||
title | ||
} | ||
} | ||
}`, | ||
variables: {}, | ||
}), | ||
}); | ||
|
||
if (!linearResponse.ok) { | ||
throw new Error("Failed to create issue in Linear"); | ||
} | ||
|
||
const parsedLinearResponse = await linearResponse.json(); | ||
const identifier = parsedLinearResponse.data.issueCreate.issue.identifier; | ||
|
||
await fetch(process.env.FEEDBACK_WEBHOOK as string, { | ||
method: "POST", | ||
headers: { "Content-Type": "application/json" }, | ||
body: JSON.stringify({ | ||
content: null, | ||
embeds: [ | ||
{ | ||
title: `<a:sdvUh:1220462519466852493> New bug report! (${identifier})`, | ||
url: `https://linear.app/stardew/issue/${identifier}`, | ||
color: null, | ||
fields: [ | ||
{ | ||
name: "What happened?", | ||
value: `${body.short}`, | ||
}, | ||
{ | ||
name: "What were you doing when this happened?", | ||
value: `${body.long}`, | ||
}, | ||
], | ||
author: { | ||
name: `${body.user.discord_name} (${body.user.discord_id})`, | ||
url: "https://cdn.discordapp.com/embed/avatars/0.png", | ||
}, | ||
footer: { | ||
text: `Turnstile: ${outcome.challenge_ts} | IP: ${ip}`, | ||
}, | ||
}, | ||
], | ||
attachments: [], | ||
}), | ||
}); | ||
|
||
return NextResponse.json({ identifier }); | ||
} catch (error: any) { | ||
console.error("Error processing bug report:", error); | ||
return NextResponse.json({ error: error.message }, { status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { NextRequest, NextResponse } from "next/server"; | ||
|
||
async function turnstile(token: string, ip: string | null) { | ||
const formData = new URLSearchParams(); | ||
|
||
formData.append("secret", process.env.TURNSTILE_KEY as string); | ||
formData.append("response", token); | ||
|
||
if (ip) { | ||
formData.append("remoteip", ip); | ||
} | ||
|
||
const url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"; | ||
|
||
const result = await fetch(url, { | ||
body: formData, | ||
method: "POST", | ||
}); | ||
|
||
return (await result.json()) as | ||
| { | ||
success: true; | ||
challenge_ts: string; | ||
hostname: string; | ||
"error-codes": string[]; | ||
action: string; | ||
cdata: string; | ||
} | ||
| { | ||
success: false; | ||
"error-codes": [string, ...string[]]; | ||
}; | ||
} | ||
|
||
export async function POST(request: NextRequest) { | ||
try { | ||
const body = await request.json(); | ||
|
||
const forwardedFor = request.headers.get("x-forwarded-for"); | ||
const ip = | ||
forwardedFor?.split(",")[0] ?? | ||
request.headers.get("x-real-ip") ?? | ||
request.headers.get("cf-connecting-ip") ?? | ||
null; | ||
|
||
const outcome = await turnstile(body.turnstile, ip); | ||
|
||
if (!outcome.success) { | ||
return new NextResponse(null, { status: 400 }); | ||
} | ||
|
||
await fetch(process.env.FEEDBACK_WEBHOOK as string, { | ||
method: "POST", | ||
headers: { "Content-Type": "application/json" }, | ||
body: JSON.stringify({ | ||
embeds: [ | ||
{ | ||
author: { | ||
name: `${body.user.discord_name} (${body.user.discord_id})`, | ||
icon_url: body.user.discord_avatar | ||
? `https://cdn.discordapp.com/avatars/${body.user.discord_id}/${body.user.discord_avatar}.png` | ||
: `https://cdn.discordapp.com/embed/avatars/0.png`, | ||
}, | ||
title: "<a:SDVowo:1018861004190400513> Feedback recieved!", | ||
description: body.body, | ||
footer: { | ||
text: `Turnstile: ${outcome.challenge_ts} | IP: ${ip}`, | ||
}, | ||
}, | ||
], | ||
}), | ||
}); | ||
|
||
return NextResponse.json({}); | ||
} catch (error: any) { | ||
return NextResponse.json({ error: error.message }, { status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import * as schema from "$drizzle/schema"; | ||
import { db } from "@/db"; | ||
import { eq } from "drizzle-orm"; | ||
import { NextResponse } from "next/server"; | ||
import { type NextRequest } from "next/server"; | ||
import { getUID } from "./saves/route"; | ||
|
||
export async function GET(request: NextRequest) { | ||
try { | ||
const uid = await getUID(); | ||
if (!uid) { | ||
return new NextResponse(null, { status: 401 }); | ||
} | ||
|
||
const [user] = await db | ||
.select() | ||
.from(schema.users) | ||
.where(eq(schema.users.id, uid)) | ||
.limit(1); | ||
|
||
return NextResponse.json(user); | ||
} catch (error: any) { | ||
return NextResponse.json({ error: error.message }, { status: 500 }); | ||
} | ||
} |
Oops, something went wrong.