feat: add gender field to user profile and update related components

This commit is contained in:
ngthanhvu
2026-07-24 04:55:39 -04:00
parent 541cb66c33
commit 6ad96873a7
11 changed files with 693 additions and 30 deletions
+1
View File
@@ -28,5 +28,6 @@ export default defineEventHandler(async (event) => {
name: user.name,
role: user.role,
avatar: user.avatar,
gender: user.gender,
}
})
+21 -15
View File
@@ -1,6 +1,6 @@
import { users } from '../../database/schema'
import { eq } from 'drizzle-orm'
import { getTokenFromEvent } from '../../utils/auth'
import { getTokenFromEvent, verifyToken } from '../../utils/auth'
export default defineEventHandler(async (event) => {
const db = useDb()
@@ -11,24 +11,30 @@ export default defineEventHandler(async (event) => {
throw createError({ statusCode: 401, message: 'Chưa đăng nhập' })
}
const name = typeof body.name === 'string' ? body.name.trim() : ''
if (!name) {
throw createError({ statusCode: 400, message: 'Tên hiển thị không được để trống' })
}
if (name.length > 50) {
throw createError({ statusCode: 400, message: 'Tên hiển thị tối đa 50 ký tự' })
}
const payload = verifyToken(token)
if (!payload) {
throw createError({ statusCode: 401, message: 'Token không hợp lệ' })
}
await db.update(users)
.set({ name })
.where(eq(users.id, payload.id))
const updates: Record<string, any> = {}
return { message: 'Cập nhật tên thành công!' }
const name = typeof body.name === 'string' ? body.name.trim() : ''
if (name) {
if (name.length > 50) {
throw createError({ statusCode: 400, message: 'Tên hiển thị tối đa 50 ký tự' })
}
updates.name = name
}
if (['male', 'female', 'other', ''].includes(body.gender)) {
updates.gender = body.gender || null
}
if (!Object.keys(updates).length) {
throw createError({ statusCode: 400, message: 'Không có dữ liệu cập nhật' })
}
await db.update(users).set(updates).where(eq(users.id, payload.id))
return { message: 'Cập nhật thành công!' }
})
+3
View File
@@ -36,6 +36,7 @@ export default defineEventHandler(async (event) => {
userName: users.name,
userAvatar: users.avatar,
userRole: users.role,
userGender: users.gender,
source: comments.source,
slug: comments.slug,
movieName: comments.movieName,
@@ -75,6 +76,7 @@ export default defineEventHandler(async (event) => {
userName: rep.anonymous ? 'Ẩn danh' : (rep.userName || 'Ẩn danh'),
userAvatar: rep.anonymous ? null : rep.userAvatar,
userRole: rep.userRole,
userGender: rep.userGender,
parentId: rep.parentId,
content: rep.content,
pinned: rep.pinned || false,
@@ -97,6 +99,7 @@ export default defineEventHandler(async (event) => {
userName: users.name,
userAvatar: users.avatar,
userRole: users.role,
userGender: users.gender,
parentId: comments.parentId,
content: comments.content,
pinned: comments.pinned,
@@ -0,0 +1 @@
ALTER TABLE `users` ADD `gender` varchar(20);
@@ -0,0 +1,566 @@
{
"version": "5",
"dialect": "mysql",
"id": "cdff5cf9-c17b-4367-a3db-46bd089b4b44",
"prevId": "80c783b0-5942-4747-b8da-78c937b01d64",
"tables": {
"comment_votes": {
"name": "comment_votes",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"user_id": {
"name": "user_id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"comment_id": {
"name": "comment_id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"vote": {
"name": "vote",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
}
},
"indexes": {
"idx_user_comment": {
"name": "idx_user_comment",
"columns": [
"user_id",
"comment_id"
],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"comment_votes_id": {
"name": "comment_votes_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"comments": {
"name": "comments",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"user_id": {
"name": "user_id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"source": {
"name": "source",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "''"
},
"slug": {
"name": "slug",
"type": "varchar(500)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"movie_name": {
"name": "movie_name",
"type": "varchar(500)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"parent_id": {
"name": "parent_id",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"pinned": {
"name": "pinned",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"spoiler": {
"name": "spoiler",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"anonymous": {
"name": "anonymous",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"like_count": {
"name": "like_count",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"dislike_count": {
"name": "dislike_count",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {
"idx_source_slug": {
"name": "idx_source_slug",
"columns": [
"source",
"slug"
],
"isUnique": false
},
"idx_user_id": {
"name": "idx_user_id",
"columns": [
"user_id"
],
"isUnique": false
},
"idx_parent_id": {
"name": "idx_parent_id",
"columns": [
"parent_id"
],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {
"comments_id": {
"name": "comments_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"movies": {
"name": "movies",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"source": {
"name": "source",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"slug": {
"name": "slug",
"type": "varchar(500)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(500)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"origin_name": {
"name": "origin_name",
"type": "varchar(500)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"thumb": {
"name": "thumb",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"poster": {
"name": "poster",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"year": {
"name": "year",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"time": {
"name": "time",
"type": "varchar(100)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"episode": {
"name": "episode",
"type": "varchar(100)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"episode_total": {
"name": "episode_total",
"type": "varchar(100)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"quality": {
"name": "quality",
"type": "varchar(50)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"lang": {
"name": "lang",
"type": "varchar(50)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"type": {
"name": "type",
"type": "varchar(50)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"rating": {
"name": "rating",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"views": {
"name": "views",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"categories": {
"name": "categories",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"countries": {
"name": "countries",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sources": {
"name": "sources",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"custom_poster": {
"name": "custom_poster",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"custom_thumb": {
"name": "custom_thumb",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"custom_content": {
"name": "custom_content",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"custom_episodes": {
"name": "custom_episodes",
"type": "json",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"active": {
"name": "active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"api_updated_at": {
"name": "api_updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"synced_at": {
"name": "synced_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"movies_id": {
"name": "movies_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"name": {
"name": "name",
"type": "varchar(200)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"password": {
"name": "password",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"role": {
"name": "role",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'user'"
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"gender": {
"name": "gender",
"type": "varchar(20)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"reset_token": {
"name": "reset_token",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"reset_token_expires": {
"name": "reset_token_expires",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"active": {
"name": "active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"users_id": {
"name": "users_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"columns": [
"email"
]
}
},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}
@@ -85,6 +85,13 @@
"when": 1784853783915,
"tag": "0011_magenta_jack_flag",
"breakpoints": true
},
{
"idx": 12,
"version": "5",
"when": 1784882595519,
"tag": "0012_bumpy_the_watchers",
"breakpoints": true
}
]
}
+1
View File
@@ -7,6 +7,7 @@ export const users = mysqlTable('users', {
password: varchar('password', { length: 255 }).notNull(),
role: varchar('role', { length: 50 }).notNull().default('user'),
avatar: text('avatar'),
gender: varchar('gender', { length: 20 }),
resetToken: varchar('reset_token', { length: 255 }),
resetTokenExpires: timestamp('reset_token_expires'),
active: boolean('active').notNull().default(true),