v3: added onboarding email on account creation

This commit is contained in:
khannurien
2026-03-30 14:55:30 +00:00
parent cbb3505139
commit 378b3ffa46
27 changed files with 404 additions and 59 deletions

View File

@@ -37,7 +37,11 @@ router.get("/", async (ctx) => {
ctx.response.body = {
success: true,
data: {
dumps: { items: dumpItems, total: dumpTotal, hasMore: page * limit < dumpTotal },
dumps: {
items: dumpItems,
total: dumpTotal,
hasMore: page * limit < dumpTotal,
},
users,
playlists,
},

View File

@@ -21,6 +21,9 @@ import {
updateUser,
} from "../services/user-service.ts";
import { redeemInvite, validateInvite } from "../services/invite-service.ts";
import { isEmailEnabled, sendEmail } from "../services/email-service.ts";
import { FROM_EMAIL, OG_SITE_NAME, WELCOME_EMAIL_BODY } from "../config.ts";
import { marked } from "marked";
import { broadcastUserUpdated } from "../services/ws-service.ts";
import {
getDumpsByUser,
@@ -53,6 +56,20 @@ router.post("/register", async (ctx) => {
console.error("[register] redeemInvite failed (user created):", err);
}
// Send welcome email (fire-and-forget)
if (isEmailEnabled()) {
const emailMarkdown = WELCOME_EMAIL_BODY
.replaceAll("{{username}}", user.username)
.replaceAll("{{site_name}}", OG_SITE_NAME);
sendEmail({
from: FROM_EMAIL,
to: user.email,
subject: `Welcome to ${OG_SITE_NAME}`,
text: emailMarkdown,
html: await marked(emailMarkdown),
}).catch((err) => console.error("[register] welcome email failed:", err));
}
const authToken = await createJWT({
userId: user.id,
username: user.username,
@@ -153,7 +170,7 @@ router.patch("/me", authMiddleware, async (ctx: AuthContext) => {
);
}
const updated = await updateUser(ctx.state.user.userId, body);
const { passwordHash: _, ...publicUser } = updated;
const { passwordHash: _, email: _email, ...publicUser } = updated;
broadcastUserUpdated(publicUser);
ctx.response.body = { success: true, data: publicUser };
});
@@ -168,7 +185,7 @@ router.get("/search", (ctx) => {
// Public user profile by internal ID (used when only userId is available, e.g. dump.userId)
router.get("/by-id/:userId", (ctx) => {
const user = getUserById(ctx.params.userId);
const { passwordHash: _, ...publicUser } = user;
const { passwordHash: _, email: _email, ...publicUser } = user;
ctx.response.body = { success: true, data: publicUser };
});
@@ -211,7 +228,7 @@ router.get("/:username/playlists", async (ctx) => {
// Public user profile by username (no passwordHash)
router.get("/:username", (ctx) => {
const user = getUserByUsername(ctx.params.username);
const { passwordHash: _, ...publicUser } = user;
const { passwordHash: _, email: _email, ...publicUser } = user;
ctx.response.body = { success: true, data: publicUser };
});