mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-06-28 06:34:15 +00:00
feat: add back edit page and fix profile settings
This commit is contained in:
parent
e81f054e3a
commit
63dbaf13fa
31 changed files with 1246 additions and 1292 deletions
|
|
@ -4,7 +4,7 @@ import { auth } from "@/lib/auth";
|
|||
import { prisma } from "@/lib/prisma";
|
||||
import { idSchema } from "@tomodachi-share/shared/schemas";
|
||||
|
||||
export async function PATCH(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { settings } from "@/lib/settings";
|
||||
import { settings } from "../../../../lib/settings";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({ success: true, value: settings.canSubmit });
|
||||
}
|
||||
|
||||
export async function PATCH(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { settings } from "@/lib/settings";
|
||||
import { settings } from "../../../../lib/settings";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({ success: true, value: settings.queueEnabled });
|
||||
}
|
||||
|
||||
export async function PATCH(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { auth } from "@/lib/auth";
|
|||
import { prisma } from "@/lib/prisma";
|
||||
import { generateMetadataImage } from "@/lib/images";
|
||||
|
||||
export async function PATCH() {
|
||||
export async function POST() {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { auth } from "@/lib/auth";
|
|||
import { prisma } from "@/lib/prisma";
|
||||
import { RateLimit } from "@/lib/rate-limit";
|
||||
|
||||
export async function PATCH(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { prisma } from "@/lib/prisma";
|
|||
import { userNameSchema } from "@tomodachi-share/shared/schemas";
|
||||
import { RateLimit } from "@/lib/rate-limit";
|
||||
|
||||
export async function PATCH(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session || !session.user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const formDataSchema = z.object({
|
|||
image: z.union([z.instanceof(File), z.any()]).optional(),
|
||||
});
|
||||
|
||||
export async function PATCH(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { idSchema, nameSchema, switchMiiInstructionsSchema, tagsSchema } from "@
|
|||
import { generateMetadataImage, validateImage } from "@/lib/images";
|
||||
import { RateLimit } from "@/lib/rate-limit";
|
||||
import { minifyInstructions, SwitchMiiInstructions } from "@tomodachi-share/shared";
|
||||
import { settings } from "@/lib/settings";
|
||||
import { settings } from "../../../../../lib/settings";
|
||||
|
||||
const uploadsDirectory = path.join(process.cwd(), "uploads", "mii");
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ const editSchema = z.object({
|
|||
image3: z.union([z.instanceof(File), z.any()]).optional(),
|
||||
});
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { prisma } from "@/lib/prisma";
|
|||
import { idSchema } from "@tomodachi-share/shared/schemas";
|
||||
import { RateLimit } from "@/lib/rate-limit";
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await auth();
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import Mii from "../../../../../shared/src/mii.js/mii";
|
|||
import { convertQrCode, minifyInstructions, ThreeDsTomodachiLifeMii } from "@tomodachi-share/shared";
|
||||
|
||||
import { SwitchMiiInstructions } from "@tomodachi-share/shared";
|
||||
import { settings } from "@/lib/settings";
|
||||
import { settings } from "../../../lib/settings";
|
||||
|
||||
const uploadsDirectory = path.join(process.cwd(), "uploads", "mii");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
import { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { Icon } from "@iconify/react";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Leaving TomodachiShare",
|
||||
description: "Warning: You are leaving TomodachiShare, proceed with caution",
|
||||
};
|
||||
|
||||
interface Props {
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||
}
|
||||
|
||||
export default async function LinkOutPage({ searchParams }: Props) {
|
||||
const url = (await searchParams).url;
|
||||
if (!url || Array.isArray(url)) redirect("/");
|
||||
|
||||
let parsed: URL;
|
||||
try {
|
||||
parsed = new URL(url);
|
||||
} catch {
|
||||
redirect("/"); // redirect if URL is invalid
|
||||
}
|
||||
|
||||
// Next.js doesn't allow attacks like these but you can never be too safe
|
||||
if (!["http:", "https:"].includes(parsed.protocol)) redirect("/");
|
||||
|
||||
const isSafe = Array.from(SAFE_LINKS).some((domain) => parsed.hostname === domain || parsed.hostname.endsWith(`.${domain}`));
|
||||
if (isSafe) redirect(url);
|
||||
|
||||
return (
|
||||
<div className="grow flex items-center justify-center">
|
||||
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl shadow-lg py-8 px-6 max-w-md w-full text-center flex flex-col items-center">
|
||||
<h2 className="text-3xl font-black flex items-center gap-2 mb-1">
|
||||
<Icon icon="mingcute:alert-fill" className="text-5xl" />
|
||||
Warning
|
||||
</h2>
|
||||
<p>You're attempting to leave TomodachiShare island! The destination website is potentially dangerous.</p>
|
||||
|
||||
<div className="bg-zinc-100 border border-zinc-300 rounded-md p-2 break-all w-full mt-4">
|
||||
<code className="font-mono text-sm">{url}</code>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center gap-2">
|
||||
<Link href="/" className="pill button gap-2 mt-8 w-fit self-center bg-zinc-100! border-zinc-300! hover:bg-zinc-300!">
|
||||
<Icon icon="ic:round-home" fontSize={24} />
|
||||
Travel Back
|
||||
</Link>
|
||||
<Link href={url} target="_blank" rel="noopener noreferrer" className="pill button gap-2 mt-8 w-fit self-center">
|
||||
<Icon icon="ic:round-open-in-new" fontSize={21} />
|
||||
Continue
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const SAFE_LINKS = new Set([
|
||||
"tomodachishare.com",
|
||||
"trafficlunar.net",
|
||||
"youtube.com",
|
||||
"youtu.be",
|
||||
"twitter.com",
|
||||
"x.com",
|
||||
"reddit.com",
|
||||
"tiktok.com",
|
||||
"tumblr.com",
|
||||
"instagram.com",
|
||||
"wikipedia.org",
|
||||
]);
|
||||
|
|
@ -18,6 +18,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
|||
sameSite: "none",
|
||||
path: "/",
|
||||
secure: true,
|
||||
domain: process.env.NODE_ENV === "production" ? ".tomodachishare.com" : "localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
export function deepMerge<T>(target: T, source: Partial<T>): T {
|
||||
const output = structuredClone(target);
|
||||
|
||||
if (typeof source !== "object" || source === null) return output;
|
||||
|
||||
for (const key in source) {
|
||||
const sourceValue = source[key];
|
||||
const targetValue = (output as any)[key];
|
||||
|
||||
if (typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue)) {
|
||||
(output as any)[key] = deepMerge(targetValue, sourceValue);
|
||||
} else {
|
||||
(output as any)[key] = sourceValue;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue