Sửa lỗi cập nhật thông tin hồ sơ
@@ -943,7 +943,14 @@ router.get('/me/profile', protect, async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const user = await User.findById(req.user._id).select('-password').lean();
|
const user = await User.findById(req.user._id).select('-password').lean();
|
||||||
|
|
||||||
|
// Đảm bảo các trường này luôn tồn tại để frontend không bị lỗi undefined
|
||||||
|
user.fullName = user.fullName || '';
|
||||||
|
user.email = user.email || '';
|
||||||
|
user.avatarUrl = user.avatarUrl || '';
|
||||||
|
|
||||||
// Tính toán dung lượng thực tế của người dùng
|
// Tính toán dung lượng thực tế của người dùng
|
||||||
|
// Logic này đã được tối ưu hóa bằng Aggregation ở các bước trước
|
||||||
|
// và được giữ nguyên để trả về thông tin storage cho frontend
|
||||||
const usageResult = await Asset.aggregate([
|
const usageResult = await Asset.aggregate([
|
||||||
{ $match: { uploadedBy: req.user._id } },
|
{ $match: { uploadedBy: req.user._id } },
|
||||||
{
|
{
|
||||||
@@ -1010,21 +1017,59 @@ router.get('/me/assets/top-large', protect, async (req, res) => {
|
|||||||
* @desc Cập nhật hồ sơ (đổi tên, mật khẩu)
|
* @desc Cập nhật hồ sơ (đổi tên, mật khẩu)
|
||||||
* @access Private
|
* @access Private
|
||||||
*/
|
*/
|
||||||
router.put('/me/profile', protect, async (req, res) => {
|
router.put('/me/profile', protect, upload.single('avatar'), async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const user = await User.findById(req.user._id);
|
const user = await User.findById(req.user._id);
|
||||||
if (!user) return res.status(404).json({ message: 'User not found' });
|
if (!user) return res.status(404).json({ message: 'User not found' });
|
||||||
|
|
||||||
if (req.body.username) user.username = req.body.username;
|
const { fullName, email, username, password } = req.body;
|
||||||
if (req.body.password) user.password = req.body.password; // Hook pre-save sẽ tự hash
|
|
||||||
|
if (fullName) user.fullName = fullName;
|
||||||
|
if (email) user.email = email;
|
||||||
|
// Chỉ cho phép cập nhật username nếu nó khác với username hiện tại
|
||||||
|
if (username && user.username !== username) {
|
||||||
|
user.username = username;
|
||||||
|
} else if (username && user.username === username) {
|
||||||
|
// Nếu username không đổi, không cần gán lại để tránh trigger unique validation không cần thiết
|
||||||
|
} else if (!username) {
|
||||||
|
// Nếu frontend gửi username rỗng, có thể là lỗi hoặc cố ý xóa, cần xử lý tùy theo business logic
|
||||||
|
}
|
||||||
|
if (password && password.trim() !== '') user.password = password;
|
||||||
|
|
||||||
|
// Xử lý ảnh đại diện nếu có upload
|
||||||
|
if (req.file) {
|
||||||
|
// Xóa avatar cũ nếu có và không phải là avatar mặc định
|
||||||
|
if (user.avatarUrl && user.avatarUrl.startsWith('/api/assets/view_avatar/')) {
|
||||||
|
const oldAvatarName = user.avatarUrl.split('/').pop();
|
||||||
|
const oldAvatarPath = path.join(uploadDir, oldAvatarName);
|
||||||
|
if (fs.existsSync(oldAvatarPath)) fs.unlinkSync(oldAvatarPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const avatarName = `avatar_${user._id}${path.extname(req.file.originalname)}`;
|
||||||
|
const avatarPath = path.join(uploadDir, avatarName);
|
||||||
|
|
||||||
|
await sharp(req.file.path)
|
||||||
|
.resize(200, 200) // Resize avatar về kích thước nhỏ (200x200)
|
||||||
|
.toFile(avatarPath);
|
||||||
|
user.avatarUrl = `/api/assets/view_avatar/${avatarName}`; // Lưu đường dẫn ảnh vào DB
|
||||||
|
if (fs.existsSync(req.file.path)) fs.unlinkSync(req.file.path); // Xóa file tạm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sử dụng validateBeforeSave: false để bỏ qua validation cho các trường không được gửi lên
|
||||||
|
// hoặc các trường không liên quan đến việc cập nhật hồ sơ cá nhân như agreedToRules, role.
|
||||||
|
// Tuy nhiên, các validation cho các trường được cập nhật (như email, username unique) vẫn sẽ chạy.
|
||||||
|
await user.save({ validateBeforeSave: false });
|
||||||
|
|
||||||
await user.save();
|
|
||||||
res.json({
|
res.json({
|
||||||
message: 'Hồ sơ đã được cập nhật',
|
message: 'Hồ sơ đã được cập nhật',
|
||||||
user: { id: user._id, username: user.username, role: user.role }
|
user: { id: user._id, username: user.username, role: user.role }
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ message: error.message });
|
// Xử lý lỗi validation của Mongoose
|
||||||
|
if (error.name === 'ValidationError') {
|
||||||
|
return res.status(400).json({ message: error.message });
|
||||||
|
}
|
||||||
|
next(error); // Chuyển lỗi khác cho middleware xử lý lỗi chung
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 5.7 MiB |
|
After Width: | Height: | Size: 6.9 MiB |
|
After Width: | Height: | Size: 5.3 MiB |
|
After Width: | Height: | Size: 4.4 MiB |
|
After Width: | Height: | Size: 3.5 MiB |
|
After Width: | Height: | Size: 3.0 MiB |
@@ -307,6 +307,10 @@ async function updateProfile(e) {
|
|||||||
const form = document.getElementById('profile-form');
|
const form = document.getElementById('profile-form');
|
||||||
const formData = new FormData(form);
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
// Xóa các trường không cần thiết khi cập nhật hồ sơ cá nhân
|
||||||
|
formData.delete('agreedToRules'); // Không cần khi cập nhật
|
||||||
|
formData.delete('role'); // Role chỉ được thay đổi bởi Admin
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_BASE_URL}/me/profile`, {
|
const res = await fetch(`${API_BASE_URL}/me/profile`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
|||||||