好的,让我们来实现用户设置页面。这个页面将允许用户更新他们的个人信息,如用户名、电子邮件和密码。
第十部分:实现用户设置页面
- 首先,我们需要更新用户路由。在
src/routes/users.ts中添加以下内容:
import { Elysia, t } from "elysia";
import { db } from "../db";
import { users } from "../db/schema";
import { eq } from "drizzle-orm";
import { authMiddleware } from "../middleware/auth";
import bcrypt from "bcrypt";
export const userRoutes = new Elysia()
.use(authMiddleware)
.get("/users/:id", async ({ params }) => {
const user = await db.select({
id: users.id,
username: users.username,
email: users.email,
})
.from(users)
.where(eq(users.id, parseInt(params.id)))
.get();
return user;
})
.get("/settings", async ({ getCurrentUser }) => {
const user = await getCurrentUser();
if (!user) {
return null;
}
return user;
})
.patch("/settings", async ({ body, set, getCurrentUser }) => {
const currentUser = await getCurrentUser();
if (!currentUser) {
set.status = 401;
return { error: "Not authorized" };
}
const { username, email, currentPassword, newPassword } = body;
if (currentPassword) {
const isPasswordCorrect = await bcrypt.compare(currentPassword, currentUser.password);
if (!isPasswordCorrect) {
set.status = 400;
return { error: "Current password is incorrect" };
}
}
const updateData: any = {};
if (username) updateData.username = username;
if (email) updateData.email = email;
if (newPassword) {
const hashedPassword = await bcrypt.hash(newPassword, 10);
updateData.password = hashedPassword;
}
const updatedUser = await db.update(users)
.set(updateData)
.where(eq(users.id, currentUser.id))
.returning({
id: users.id,
username: users.username,
email: users.email,
})
.get();
return updatedUser;
});- 创建一个新的视图文件
src/views/settings.eta:
<% layout('./layouts/main.eta', { title: 'User Settings' }) %>
<h1>User Settings</h1>
<form hx-patch="/settings" hx-swap="outerHTML">
<div>
<label for="username">Username:</label>
<input type="text" id="username" name="username" value="<%= it.user.username %>" required>
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" value="<%= it.user.email %>" required>
</div>
<div>
<label for="currentPassword">Current Password:</label>
<input type="password" id="currentPassword" name="currentPassword">
</div>
<div>
<label for="newPassword">New Password:</label>
<input type="password" id="newPassword" name="newPassword">
</div>
<button type="submit">Update Settings</button>
</form>
<div id="message"></div>
<script>
document.body.addEventListener('htmx:afterRequest', function(event) {
if (event.detail.successful) {
document.getElementById('message').innerHTML = '<p class="success">Settings updated successfully!</p>';
} else {
document.getElementById('message').innerHTML = '<p class="error">Failed to update settings. Please try again.</p>';
}
});
</script>- 更新
src/index.ts以包含新的设置路由:
import { Elysia } from "elysia";
import { html } from "@elysiajs/html";
import { staticPlugin } from "@elysiajs/static";
import { authRoutes, auth } from "./routes/auth";
import { postRoutes } from "./routes/posts";
import { userRoutes } from "./routes/users";
import { commentRoutes } from "./routes/comments";
import { migrate } from "drizzle-orm/libsql/migrator";
import { db } from "./db";
import { renderFile } from "eta";
import path from "path";
// ... 前面的代码保持不变
const app = new Elysia()
.use(html())
.use(staticPlugin())
.use(auth)
.use(authRoutes)
.use(postRoutes)
.use(userRoutes)
.use(commentRoutes)
// ... 其他路由保持不变
.get("/settings", async ({ set, getCurrentUser }) => {
const user = await getCurrentUser();
if (!user) {
set.redirect = "/login";
return;
}
set.headers['Content-Type'] = 'text/html';
return await renderFile(path.join(__dirname, "views", "settings.eta"), { user });
})
.listen(3000);
console.log(`Server is running at ${app.server?.hostname}:${app.server?.port}`);- 更新
src/views/layouts/main.eta以添加设置页面的链接:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= it.title %> - My Blog</title>
<link rel="stylesheet" href="/styles/main.css">
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/posts/new">New Post</a>
<% if (it.user) { %>
<a href="/settings">Settings</a>
<a href="/logout">Logout</a>
<% } else { %>
<a href="/login">Login</a>
<a href="/register">Register</a>
<% } %>
</nav>
</header>
<main>
<%~ it.body %>
</main>
<footer>
<p>© 2023 My Blog</p>
</footer>
</body>
</html>- 更新
public/styles/main.css以添加设置页面的样式:
/* ... 前面的样式保持不变 */
form {
max-width: 400px;
margin: 0 auto;
}
form div {
margin-bottom: 1rem;
}
form label {
display: block;
margin-bottom: 0.5rem;
}
form input {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}
form button {
background-color: #007bff;
color: white;
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
form button:hover {
background-color: #0056b3;
}
.success {
color: green;
font-weight: bold;
}
.error {
color: red;
font-weight: bold;
}这些更改实现了用户设置页面:
- 用户可以在设置页面上查看和更新他们的用户名和电子邮件。
- 用户可以更改他们的密码,但需要提供当前密码以验证身份。
- 使用 HTMX 实现了无刷新更新用户信息的功能。
- 添加了适当的错误处理和成功消息显示。
这个功能让用户能够管理他们的个人信息,提高了用户体验和账户安全性。
接下来,我们可以实现 RSS 订阅功能。您希望继续这个方向吗,或者有其他想法?