Todo list updated
cgen-7dee112ec2a44f7eba17438c4a8b4675
This commit is contained in:
parent
83e8081a70
commit
2df17dc8ec
2 changed files with 89 additions and 12 deletions
|
|
@ -553,15 +553,53 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
|
|||
|
||||
if (error) throw error;
|
||||
|
||||
// Supabase sends the confirmation email automatically (SMTP or default provider)
|
||||
let emailSent = true;
|
||||
// Send verification email via custom SMTP (fallback: Supabase auth email)
|
||||
let emailSent = false;
|
||||
let verificationUrl: string | undefined;
|
||||
|
||||
if (data.user) {
|
||||
aethexToast.success({
|
||||
title: "Verify your email",
|
||||
description: `We sent a confirmation to ${email}.`,
|
||||
});
|
||||
try {
|
||||
// Try to send via custom SMTP server
|
||||
const verifyResponse = await fetch("/api/auth/send-verification-email", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
redirectTo,
|
||||
fullName: metadata.full_name || null,
|
||||
}),
|
||||
});
|
||||
|
||||
const verifyPayload = await verifyResponse.json().catch(() => ({}));
|
||||
|
||||
if (verifyResponse.ok && verifyPayload?.sent) {
|
||||
emailSent = true;
|
||||
aethexToast.success({
|
||||
title: "Verify your email",
|
||||
description: `We sent a confirmation to ${email}.`,
|
||||
});
|
||||
} else {
|
||||
// Custom SMTP failed, but provide manual link if available
|
||||
verificationUrl = verifyPayload?.verificationUrl || undefined;
|
||||
if (verificationUrl) {
|
||||
aethexToast.warning({
|
||||
title: "Verify your email",
|
||||
description: `We couldn't send the email automatically. Use the manual verification link in your account settings.`,
|
||||
});
|
||||
} else {
|
||||
aethexToast.info({
|
||||
title: "Account created",
|
||||
description: `Please check your email to verify your account.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (emailErr) {
|
||||
console.warn("[Auth] Failed to send verification email:", emailErr);
|
||||
aethexToast.info({
|
||||
title: "Account created",
|
||||
description: `Please check your email to verify your account.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { emailSent, verificationUrl } as const;
|
||||
|
|
|
|||
|
|
@ -536,23 +536,62 @@ export function createServer() {
|
|||
|
||||
app.post("/api/posts", async (req, res) => {
|
||||
const payload = req.body || {};
|
||||
|
||||
// Validation
|
||||
if (!payload.author_id) {
|
||||
return res.status(400).json({ error: "author_id is required" });
|
||||
}
|
||||
if (!payload.title || typeof payload.title !== "string" || !payload.title.trim()) {
|
||||
return res.status(400).json({ error: "title is required and must be a non-empty string" });
|
||||
}
|
||||
if (!payload.content || typeof payload.content !== "string" || !payload.content.trim()) {
|
||||
return res.status(400).json({ error: "content is required and must be a non-empty string" });
|
||||
}
|
||||
|
||||
// Validate author_id is a valid UUID format
|
||||
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
if (!uuidRegex.test(String(payload.author_id))) {
|
||||
return res.status(400).json({ error: "author_id must be a valid UUID" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify author exists
|
||||
const { data: author, error: authorError } = await adminSupabase
|
||||
.from("user_profiles")
|
||||
.select("id")
|
||||
.eq("id", payload.author_id)
|
||||
.single();
|
||||
|
||||
if (authorError || !author) {
|
||||
return res.status(404).json({ error: "Author not found" });
|
||||
}
|
||||
|
||||
const { data, error } = await adminSupabase
|
||||
.from("community_posts")
|
||||
.insert({
|
||||
author_id: payload.author_id,
|
||||
title: payload.title,
|
||||
content: payload.content,
|
||||
category: payload.category,
|
||||
tags: payload.tags,
|
||||
title: String(payload.title).trim(),
|
||||
content: String(payload.content).trim(),
|
||||
category: payload.category ? String(payload.category).trim() : null,
|
||||
tags: Array.isArray(payload.tags) ? payload.tags.map((t: any) => String(t).trim()) : [],
|
||||
is_published: payload.is_published ?? true,
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
if (error) return res.status(500).json({ error: error.message });
|
||||
|
||||
if (error) {
|
||||
console.error("[API] /api/posts insert error:", {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
details: (error as any).details,
|
||||
});
|
||||
return res.status(500).json({ error: error.message || "Failed to create post" });
|
||||
}
|
||||
|
||||
res.json(data);
|
||||
} catch (e: any) {
|
||||
res.status(500).json({ error: e?.message || String(e) });
|
||||
console.error("[API] /api/posts exception:", e?.message || String(e));
|
||||
res.status(500).json({ error: e?.message || "Failed to create post" });
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue