dptxa-proxy / src /pages /api /admin /nguoi-dung.js
TXAVLOG
Deploy DPTXA to Hugging Face Spaces
4bea261
Raw
History Blame Contribute Delete
9.93 kB
import { txasupabase } from '../../../lib/txasupabase.js';
export const POST = async ({ request, cookies }) => {
try {
// 1. Kiểm tra quyền Admin bảo mật
const token = cookies.get('auth_token')?.value;
let currentUser = null;
if (token) {
try {
currentUser = JSON.parse(Buffer.from(token, 'base64').toString('utf-8'));
} catch (e) {}
}
if (!currentUser || currentUser.role !== 'admin') {
return new Response(JSON.stringify({ error: 'Bạn không có quyền quản trị!' }), {
status: 403,
headers: { 'Content-Type': 'application/json' }
});
}
const body = await request.json();
const { username, usernames, action, role, email, password, province, ward, avatar_url } = body;
if (!action) {
return new Response(JSON.stringify({ error: 'Thiếu thông tin hành động (action)!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
// --- HÀNH ĐỘNG 1: THÊM MỚI NGƯỜI DÙNG (CREATE) ---
if (action === 'create') {
if (!username || !email || !password) {
return new Response(JSON.stringify({ error: 'Vui lòng cung cấp đầy đủ Tài khoản, Email và Mật khẩu!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const cleanUsername = username.trim();
const cleanEmail = email.trim();
// Kiểm tra xem tên đăng nhập đã tồn tại chưa
const existingUser = await txasupabase.getUserByUsername(cleanUsername);
if (existingUser) {
return new Response(JSON.stringify({ error: 'Tên tài khoản này đã tồn tại trên hệ thống!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
// Kiểm tra xem email đã được sử dụng chưa
const { data: existingEmail } = await txasupabase.supabase
.from('users')
.select('username')
.eq('email', cleanEmail)
.maybeSingle();
if (existingEmail) {
return new Response(JSON.stringify({ error: 'Địa chỉ Email này đã được đăng ký cho tài khoản khác!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const defaultAvatar = txasupabase.getGravatarUrl(cleanEmail);
const { data, error } = await txasupabase.supabase
.from('users')
.insert({
username: cleanUsername,
email: cleanEmail,
password: password,
province: province || '',
ward: ward || '',
role: role || 'user',
avatar_url: avatar_url || defaultAvatar,
favorites: [],
history: [],
created_at: new Date().toISOString()
})
.select()
.single();
if (error) throw error;
// Ghi log hoạt động
await txasupabase.supabase.from('logs').insert({
action: 'user_created',
level: 'info',
message: `Admin "${currentUser.username}" đã tạo mới tài khoản "${cleanUsername}" với quyền "${role || 'user'}"`,
details: JSON.stringify({ username: cleanUsername, role: role || 'user', created_by: currentUser.username })
});
return new Response(JSON.stringify({
success: true,
message: `Đã tạo tài khoản "${cleanUsername}" thành công!`,
user: data
}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
// --- HÀNH ĐỘNG 2: CHỈNH SỬA THÔNG TIN NGƯỜI DÙNG (UPDATE) ---
if (action === 'update') {
if (!username) {
return new Response(JSON.stringify({ error: 'Thiếu Tên tài khoản cần cập nhật!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
// Chặn Admin tự hạ quyền của chính mình khi cập nhật
if (username === currentUser.username && role === 'user') {
return new Response(JSON.stringify({ error: 'Bạn không thể tự hạ quyền quản trị của chính mình!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
// Kiểm tra trùng lặp email nếu email bị thay đổi
if (email) {
const cleanEmail = email.trim();
const { data: dupEmail } = await txasupabase.supabase
.from('users')
.select('username')
.eq('email', cleanEmail)
.neq('username', username)
.maybeSingle();
if (dupEmail) {
return new Response(JSON.stringify({ error: 'Địa chỉ Email này đã được sử dụng bởi tài khoản khác!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
}
const updateData = {
email: email ? email.trim() : undefined,
province: province !== undefined ? province : undefined,
ward: ward !== undefined ? ward : undefined,
role: role !== undefined ? role : undefined,
avatar_url: avatar_url !== undefined ? avatar_url : undefined
};
// Chỉ cập nhật mật khẩu mới nếu được điền
if (password && password.trim() !== '') {
updateData.password = password;
}
// Loại bỏ các trường undefined để tránh ghi đè null vô lý
Object.keys(updateData).forEach(key => updateData[key] === undefined && delete updateData[key]);
const { data, error } = await txasupabase.supabase
.from('users')
.update(updateData)
.eq('username', username)
.select()
.single();
if (error) throw error;
// Ghi log hoạt động
await txasupabase.supabase.from('logs').insert({
action: 'user_updated',
level: 'info',
message: `Admin "${currentUser.username}" đã cập nhật thông tin tài khoản "${username}"`,
details: JSON.stringify({ username, updated_fields: Object.keys(updateData), updated_by: currentUser.username })
});
return new Response(JSON.stringify({
success: true,
message: `Đã cập nhật thông tin tài khoản "${username}" thành công!`,
user: data
}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
// --- HÀNH ĐỘNG 3: ĐỔI VAI TRÒ NHANH (CHANGE ROLE) ---
if (action === 'change_role') {
if ((!username && !usernames) || !role) {
return new Response(JSON.stringify({ error: 'Thiếu thông tin người dùng hoặc vai trò!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const userList = usernames ? usernames : [username];
// Ngăn không cho admin tự hạ quyền của chính mình
if (userList.includes(currentUser.username)) {
return new Response(JSON.stringify({ error: 'Bạn không thể tự hạ quyền hoặc thay đổi vai trò của chính mình!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const { error } = await txasupabase.supabase
.from('users')
.update({ role: role })
.in('username', userList);
if (error) throw error;
await txasupabase.supabase.from('logs').insert({
action: 'user_role_changed_bulk',
level: 'info',
message: `Admin "${currentUser.username}" đã đổi quyền của ${userList.length} tài khoản thành "${role}"`,
details: JSON.stringify({ usernames: userList, new_role: role, changed_by: currentUser.username })
});
return new Response(JSON.stringify({
success: true,
message: `Đã chuyển đổi quyền của ${userList.length} tài khoản thành công!`
}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
// --- HÀNH ĐỘNG 4: XÓA TÀI KHOẢN (DELETE & BULK DELETE) ---
if (action === 'delete') {
const userList = usernames ? usernames : [username];
// Ngăn không cho admin tự xóa chính mình
const cleanUserList = userList.filter(u => u !== currentUser.username);
if (cleanUserList.length === 0) {
return new Response(JSON.stringify({ error: 'Không thể tự xóa tài khoản quản trị của chính bạn!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const { error } = await txasupabase.supabase
.from('users')
.delete()
.in('username', cleanUserList);
if (error) throw error;
await txasupabase.supabase.from('logs').insert({
action: 'user_deleted_bulk',
level: 'warn',
message: `Admin "${currentUser.username}" đã xóa đồng loạt ${cleanUserList.length} tài khoản người dùng`,
details: JSON.stringify({ deleted_usernames: cleanUserList, deleted_by: currentUser.username })
});
return new Response(JSON.stringify({
success: true,
message: `Đã xóa thành công ${cleanUserList.length} tài khoản người dùng!`
}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
return new Response(JSON.stringify({ error: 'Hành động không hợp lệ!' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
} catch (err) {
console.error('Error handling admin user management API:', err);
return new Response(JSON.stringify({ error: err.message || 'Có lỗi xảy ra trên hệ thống!' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
};