feat: support admin to transfer links to other accounts

This commit is contained in:
oiov
2025-11-08 19:56:58 +08:00
parent 3d24f9bd71
commit 0cb3946b39
4 changed files with 83 additions and 17 deletions

View File

@@ -1,7 +1,10 @@
import { env } from "@/env.mjs";
import { getUserRecords } from "@/lib/dto/cloudflare-dns-record";
import { updateUserShortUrl } from "@/lib/dto/short-urls";
import { checkUserStatus } from "@/lib/dto/user";
import {
updateUserShortUrl,
updateUserShortUrlAdmin,
} from "@/lib/dto/short-urls";
import { checkUserStatus, getUserByEmail } from "@/lib/dto/user";
import { getCurrentUser } from "@/lib/session";
import { createUrlSchema } from "@/lib/validations/url";
@@ -16,7 +19,7 @@ export async function POST(req: Request) {
});
}
const { data, userId } = await req.json();
const { data, userId, email } = await req.json();
if (!data?.id || !userId) {
return Response.json(`Url id is required`, {
status: 400,
@@ -24,21 +27,34 @@ export async function POST(req: Request) {
});
}
const target_user = await getUserByEmail(email);
if (!target_user) {
return Response.json("User not found", {
status: 404,
statusText: "User not found",
});
}
const { target, url, prefix, visible, active, id, expiration, password } =
createUrlSchema.parse(data);
const res = await updateUserShortUrl({
id,
userId,
userName: "",
target,
url,
prefix,
visible,
active,
expiration,
password,
});
const res = await updateUserShortUrlAdmin(
{
id,
userId: userId,
userName: "",
target,
url,
prefix,
visible,
active,
expiration,
password,
},
target_user.id,
);
if (res.status !== "success") {
console.log(res);
return Response.json(res.status, {
status: 400,
statusText: `An error occurred. ${res.status}`,
@@ -46,6 +62,7 @@ export async function POST(req: Request) {
}
return Response.json(res.data);
} catch (error) {
console.log(error);
return Response.json(error?.statusText || error, {
status: error.status || 500,
statusText: error.statusText || "Server error",

View File

@@ -61,6 +61,8 @@ export function UrlForm({
const [currentPrefix, setCurrentPrefix] = useState(initData?.prefix || "");
const [limitLen, setLimitLen] = useState(3);
const t = useTranslations("List");
const isAdmin = action.indexOf("admin") > -1;
const [email, setEmail] = useState(initData?.user?.email);
const {
handleSubmit,
@@ -157,7 +159,7 @@ export function UrlForm({
if (type === "edit") {
const response = await fetch(`${action}/update`, {
method: "POST",
body: JSON.stringify({ data, userId: initData?.userId }),
body: JSON.stringify({ data, userId: initData?.userId, email }),
});
if (!response.ok || response.status !== 200) {
toast.error("Update Failed", {
@@ -203,6 +205,25 @@ export function UrlForm({
{type === "add" ? t("Create short link") : t("Edit short link")}
</div>
<form className="p-4" onSubmit={onSubmit}>
{isAdmin && (
<div className="items-center justify-start gap-4 md:flex">
<FormSectionColumns required title={t("User email")}>
<div className="flex w-full items-center gap-2">
<Label className="sr-only" htmlFor="content">
{t("User email")}
</Label>
<Input
id="email"
className="flex-1 shadow-inner"
size={32}
value={email || ""}
onChange={(e) => setEmail(e.target.value)}
// disabled={type === "edit"}
/>
</div>
</FormSectionColumns>
</div>
)}
<div className="items-center justify-start gap-4 md:flex">
<FormSectionColumns title={t("Target URL")} required>
<div className="flex w-full items-center gap-2">

View File

@@ -313,6 +313,34 @@ export async function updateUserShortUrl(data: ShortUrlFormData) {
}
}
export async function updateUserShortUrlAdmin(
data: ShortUrlFormData,
newUserId,
) {
try {
const res = await prisma.userUrl.update({
where: {
id: data.id,
userId: data.userId,
},
data: {
userId: newUserId,
target: data.target,
url: data.url,
visible: data.visible,
prefix: data.prefix,
// active: data.active,
expiration: data.expiration,
password: data.password,
updatedAt: new Date().toISOString(),
},
});
return { status: "success", data: res };
} catch (error) {
return { status: error };
}
}
export async function updateUserShortUrlActive(
userId: string,
id: string,

File diff suppressed because one or more lines are too long