Skip to content

Commit f6c25f4

Browse files
author
yangtao
committed
迁移postgres到sqlite,减少环境变量的手动配置
1 parent fafa25e commit f6c25f4

19 files changed

Lines changed: 545 additions & 426 deletions

File tree

Dockerfile

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ FROM node:18-alpine AS builder
2525
# 设置pnpm(复用deps阶段的环境更好,但这里保持独立性)
2626
RUN corepack enable && corepack prepare pnpm@latest --activate
2727

28+
# 设置生产环境变量
29+
ENV NODE_ENV=production \
30+
NEXT_TELEMETRY_DISABLED=1
31+
2832
WORKDIR /app
2933

3034
# 复制deps阶段的所有内容(包括node_modules和配置文件)
@@ -42,14 +46,15 @@ ARG VERSION
4246
LABEL version=${VERSION}
4347
LABEL org.opencontainers.image.version=${VERSION}
4448

49+
# 设置生产环境变量
50+
ENV NODE_ENV=production \
51+
NEXT_TELEMETRY_DISABLED=1
52+
4553
# 设置pnpm(使用corepack而不是npm)
4654
RUN corepack enable && corepack prepare pnpm@latest --activate
4755

4856
WORKDIR /app
4957

50-
# 合并所有生产环境的设置
51-
RUN apk add --no-cache postgresql-client
52-
5358
# 复制package文件
5459
COPY --from=deps /app/package.json /app/pnpm-lock.yaml /app/pnpm-workspace.yaml ./
5560

@@ -70,11 +75,6 @@ COPY --from=builder /app/types ./types
7075
COPY --from=builder /app/tsconfig.json ./tsconfig.json
7176
COPY --from=builder /app/next.config.js ./next.config.js
7277

73-
# 生成Prisma客户端并设置权限
74-
#USER nextjs
75-
#RUN pnpm exec prisma generate && \
76-
# chown -R nextjs:nodejs /app
77-
7878
# 生成Prisma客户端
7979
RUN pnpm exec prisma generate
8080

@@ -89,10 +89,6 @@ ENV APP_VERSION=${VERSION}
8989
CMD ["sh", "-c", "\
9090
echo '🚀 启动NodePass生产环境 (整合SSE服务)...' && \
9191
echo '📦 当前版本: '${APP_VERSION} && \
92-
echo '⏳ 等待数据库连接...' && \
93-
while ! pg_isready -h postgres -p 5432 -U ${POSTGRES_USER:-nodepass} -q; do \
94-
echo '⏳ 等待PostgreSQL启动...' && sleep 2; \
95-
done && \
9692
echo '📊 运行数据库迁移...' && \
9793
pnpm exec prisma migrate deploy && \
9894
echo '🎯 启动整合生产服务...' && \
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import { cookies } from 'next/headers';
3+
import { z } from 'zod';
4+
import { validateSession, getSessionUser, changeUsername } from '@/lib/server/auth-service';
5+
6+
// 用户名修改请求验证schema
7+
const changeUsernameSchema = z.object({
8+
newUsername: z.string()
9+
.min(2, '用户名至少需要2个字符')
10+
.max(20, '用户名最多20个字符')
11+
.regex(/^[a-zA-Z0-9_\u4e00-\u9fa5]+$/, '用户名只能包含字母、数字、下划线和中文')
12+
});
13+
14+
/**
15+
* POST - 修改用户名
16+
* 使用本地auth-service处理用户名修改
17+
*/
18+
export async function POST(request: NextRequest) {
19+
try {
20+
// 验证用户登录状态
21+
const cookieStore = await cookies();
22+
const sessionCookie = cookieStore.get('session');
23+
24+
if (!sessionCookie) {
25+
return NextResponse.json(
26+
{ success: false, message: '用户未登录' },
27+
{ status: 401 }
28+
);
29+
}
30+
31+
// 验证会话是否有效
32+
const isValidSession = await validateSession(sessionCookie.value);
33+
if (!isValidSession) {
34+
return NextResponse.json(
35+
{ success: false, message: '会话已过期,请重新登录' },
36+
{ status: 401 }
37+
);
38+
}
39+
40+
// 获取会话用户信息
41+
const sessionUser = await getSessionUser(sessionCookie.value);
42+
if (!sessionUser) {
43+
return NextResponse.json(
44+
{ success: false, message: '无法获取用户信息' },
45+
{ status: 401 }
46+
);
47+
}
48+
49+
// 解析请求体
50+
const body = await request.json();
51+
const validationResult = changeUsernameSchema.safeParse(body);
52+
53+
if (!validationResult.success) {
54+
return NextResponse.json(
55+
{
56+
success: false,
57+
message: '请求数据验证失败',
58+
errors: validationResult.error.errors
59+
},
60+
{ status: 400 }
61+
);
62+
}
63+
64+
const { newUsername } = validationResult.data;
65+
66+
console.log('[修改用户名API] 开始处理用户名修改请求:', {
67+
currentUsername: sessionUser.username,
68+
newUsername: newUsername,
69+
sessionId: sessionCookie.value
70+
});
71+
72+
// 使用本地auth-service修改用户名
73+
const result = await changeUsername(sessionUser.username, newUsername);
74+
75+
if (result.success) {
76+
console.log('[修改用户名API] 用户名修改成功:', {
77+
oldUsername: sessionUser.username,
78+
newUsername: newUsername
79+
});
80+
81+
return NextResponse.json({
82+
success: true,
83+
message: result.message
84+
});
85+
} else {
86+
console.log('[修改用户名API] 用户名修改失败:', {
87+
username: sessionUser.username,
88+
message: result.message
89+
});
90+
91+
return NextResponse.json(
92+
{
93+
success: false,
94+
message: result.message
95+
},
96+
{ status: 400 }
97+
);
98+
}
99+
100+
} catch (error) {
101+
console.error('[修改用户名API] 处理用户名修改请求时发生错误:', error);
102+
return NextResponse.json(
103+
{
104+
success: false,
105+
message: '服务器内部错误'
106+
},
107+
{ status: 500 }
108+
);
109+
}
110+
}

app/login/layout.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,39 @@
1+
"use client";
2+
13
import { ReactNode } from 'react';
4+
import { Button } from "@heroui/react";
5+
import { Icon } from "@iconify/react";
6+
import { useTheme } from "next-themes";
27

38
interface LoginLayoutProps {
49
children: ReactNode;
510
}
611

712
export default function LoginLayout({ children }: LoginLayoutProps) {
13+
const { theme, setTheme } = useTheme();
14+
15+
const toggleTheme = () => {
16+
setTheme(theme === 'light' ? 'dark' : 'light');
17+
};
18+
819
return (
9-
<div className="min-h-screen bg-background">
20+
<div className="min-h-screen bg-background relative">
1021
{children}
22+
23+
{/* 浮动主题切换按钮 */}
24+
<Button
25+
isIconOnly
26+
variant="flat"
27+
className="fixed bottom-4 right-4 rounded-full"
28+
onClick={toggleTheme}
29+
aria-label="切换主题"
30+
>
31+
<Icon
32+
icon={theme === 'light' ? "solar:moon-linear" : "solar:sun-2-linear"}
33+
width={24}
34+
className="text-foreground"
35+
/>
36+
</Button>
1137
</div>
1238
);
1339
}

0 commit comments

Comments
 (0)