Browse Source

Merge branch 'feature/comment-email-config'

main
npmrun 3 weeks ago
parent
commit
7e0d240046
  1. 11
      app/pages/me/profile/index.vue
  2. 17
      server/api/me/profile.put.ts
  3. 4
      server/service/profile/index.ts

11
app/pages/me/profile/index.vue

@ -9,6 +9,7 @@ const toast = useToast()
type ProfileGet = {
profile: {
email: string | null
nickname: string | null
avatar: string | null
avatarVisibility: string
@ -27,6 +28,7 @@ type MeConfigGet = {
}
const state = reactive({
email: '',
nickname: '',
avatar: '',
avatarVisibility: 'private',
@ -184,6 +186,7 @@ async function load() {
const p = profilePayload.profile
const cfg = meCfgPayload.config
state.nickname = p.nickname ?? ''
state.email = p.email ?? ''
state.avatar = p.avatar ?? ''
state.avatarVisibility = p.avatarVisibility
state.bioMarkdown = p.bioMarkdown ?? ''
@ -219,6 +222,7 @@ async function save() {
method: 'PUT',
notify: false,
body: {
email: state.email.trim() || null,
nickname: state.nickname || null,
avatar: state.avatar || null,
avatarVisibility: state.avatarVisibility,
@ -327,6 +331,13 @@ async function save() {
<UInput v-model="state.nickname" />
</UFormField>
<UFormField
label="邮箱"
name="email"
description="用于接收评论通知与测试邮件,留空表示不接收邮件通知。"
>
<UInput v-model="state.email" type="email" placeholder="you@example.com" />
</UFormField>
<UFormField
label="公开主页顶栏名称"
name="publicHomeHeaderTitle"
description="在 /@你的 slug 页面左上角显示。留空则使用全站站点名称。"

17
server/api/me/profile.put.ts

@ -1,10 +1,23 @@
import { updateProfile } from "#server/service/profile";
import { visibilitySchema } from "#server/constants/visibility";
import { isUniqueConstraintViolation } from "#server/utils/db-unique-constraint";
import { ZodError, z } from "zod";
function normalizeEmailInput(raw: string | null | undefined) {
if (raw === undefined || raw === null) {
return raw;
}
const value = raw.trim();
if (!value) {
return null;
}
return z.string().email("邮箱格式不合法").parse(value);
}
export default defineWrappedResponseHandler(async (event) => {
const user = await event.context.auth.requireUser();
const body = await readBody<{
email?: string | null;
nickname?: string | null;
avatar?: string | null;
avatarVisibility?: string;
@ -19,6 +32,7 @@ export default defineWrappedResponseHandler(async (event) => {
try {
const row = await updateProfile(user.id, {
email: normalizeEmailInput(body.email),
nickname: body.nickname,
avatar: body.avatar,
avatarVisibility:
@ -37,6 +51,9 @@ export default defineWrappedResponseHandler(async (event) => {
}
return R.success({ ok: true });
} catch (e) {
if (e instanceof ZodError) {
throw createError({ statusCode: 400, statusMessage: e.issues[0]?.message ?? "参数不合法" });
}
if (isUniqueConstraintViolation(e)) {
throw createError({ statusCode: 409, statusMessage: "公开链接 slug 已被占用" });
}

4
server/service/profile/index.ts

@ -52,6 +52,7 @@ export async function getProfileRow(userId: number) {
export async function updateProfile(
userId: number,
patch: {
email?: string | null;
nickname?: string | null;
avatar?: string | null;
avatarVisibility?: Visibility;
@ -66,6 +67,9 @@ export async function updateProfile(
) {
const updates: Record<string, unknown> = {};
if (patch.email !== undefined) {
updates.email = patch.email?.trim() || null;
}
if (patch.nickname !== undefined) {
updates.nickname = patch.nickname?.trim() || null;
}

Loading…
Cancel
Save