NoteJS/public/profile.js
Fovway e4b2be3052 feat: добавлена поддержка сессий с использованием SQLite и улучшена аутентификация
- Реализовано хранение сессий в базе данных SQLite с помощью connect-sqlite3
- Добавлены API для проверки статуса аутентификации
- Обновлены клиентские скрипты для управления состоянием аутентификации
- Добавлены проверки аутентификации на страницах входа и профиля
- Улучшено управление состоянием аутентификации в localStorage
2025-10-19 15:15:05 +07:00

306 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// DOM элементы
const avatarImage = document.getElementById("avatarImage");
const avatarPlaceholder = document.getElementById("avatarPlaceholder");
const avatarInput = document.getElementById("avatarInput");
const deleteAvatarBtn = document.getElementById("deleteAvatarBtn");
const usernameInput = document.getElementById("username");
const emailInput = document.getElementById("email");
const updateProfileBtn = document.getElementById("updateProfileBtn");
const currentPasswordInput = document.getElementById("currentPassword");
const newPasswordInput = document.getElementById("newPassword");
const confirmPasswordInput = document.getElementById("confirmPassword");
const changePasswordBtn = document.getElementById("changePasswordBtn");
const messageContainer = document.getElementById("messageContainer");
// Функция для показа сообщений
function showMessage(message, type = "success") {
messageContainer.textContent = message;
messageContainer.className = `message-container ${type}`;
messageContainer.style.display = "block";
setTimeout(() => {
messageContainer.style.display = "none";
}, 5000);
}
// Загрузка данных профиля
async function loadProfile() {
try {
const response = await fetch("/api/user");
if (!response.ok) {
throw new Error("Ошибка загрузки профиля");
}
const user = await response.json();
// Заполняем поля
usernameInput.value = user.username || "";
emailInput.value = user.email || "";
// Обрабатываем аватарку
if (user.avatar) {
avatarImage.src = user.avatar;
avatarImage.style.display = "block";
avatarPlaceholder.style.display = "none";
deleteAvatarBtn.style.display = "inline-block";
} else {
avatarImage.style.display = "none";
avatarPlaceholder.style.display = "inline-flex";
deleteAvatarBtn.style.display = "none";
}
} catch (error) {
console.error("Ошибка загрузки профиля:", error);
showMessage("Ошибка загрузки данных профиля", "error");
}
}
// Обработчик загрузки аватарки
avatarInput.addEventListener("change", async function (event) {
const file = event.target.files[0];
if (!file) return;
// Проверка размера файла (5MB)
if (file.size > 5 * 1024 * 1024) {
showMessage("Файл слишком большой. Максимальный размер: 5 МБ", "error");
return;
}
// Проверка типа файла
const allowedTypes = ["image/jpeg", "image/jpg", "image/png", "image/gif"];
if (!allowedTypes.includes(file.type)) {
showMessage(
"Недопустимый формат файла. Используйте JPG, PNG или GIF",
"error"
);
return;
}
try {
const formData = new FormData();
formData.append("avatar", file);
const response = await fetch("/api/user/avatar", {
method: "POST",
body: formData,
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Ошибка загрузки аватарки");
}
const result = await response.json();
// Обновляем отображение аватарки
avatarImage.src = result.avatar + "?t=" + Date.now(); // Добавляем timestamp для обновления кэша
avatarImage.style.display = "block";
avatarPlaceholder.style.display = "none";
deleteAvatarBtn.style.display = "inline-block";
showMessage("Аватарка успешно загружена", "success");
} catch (error) {
console.error("Ошибка загрузки аватарки:", error);
showMessage(error.message, "error");
}
// Сбрасываем input для возможности повторной загрузки того же файла
event.target.value = "";
});
// Обработчик удаления аватарки
deleteAvatarBtn.addEventListener("click", async function () {
if (!confirm("Вы уверены, что хотите удалить аватарку?")) {
return;
}
try {
const response = await fetch("/api/user/avatar", {
method: "DELETE",
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Ошибка удаления аватарки");
}
// Обновляем отображение
avatarImage.style.display = "none";
avatarPlaceholder.style.display = "inline-flex";
deleteAvatarBtn.style.display = "none";
showMessage("Аватарка успешно удалена", "success");
} catch (error) {
console.error("Ошибка удаления аватарки:", error);
showMessage(error.message, "error");
}
});
// Обработчик обновления профиля
updateProfileBtn.addEventListener("click", async function () {
const username = usernameInput.value.trim();
const email = emailInput.value.trim();
// Валидация
if (!username) {
showMessage("Логин не может быть пустым", "error");
return;
}
if (username.length < 3) {
showMessage("Логин должен быть не менее 3 символов", "error");
return;
}
if (email && !isValidEmail(email)) {
showMessage("Некорректный email адрес", "error");
return;
}
try {
const response = await fetch("/api/user/profile", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
email: email || null,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Ошибка обновления профиля");
}
const result = await response.json();
showMessage(result.message || "Профиль успешно обновлен", "success");
} catch (error) {
console.error("Ошибка обновления профиля:", error);
showMessage(error.message, "error");
}
});
// Обработчик изменения пароля
changePasswordBtn.addEventListener("click", async function () {
const currentPassword = currentPasswordInput.value;
const newPassword = newPasswordInput.value;
const confirmPassword = confirmPasswordInput.value;
// Валидация
if (!currentPassword) {
showMessage("Введите текущий пароль", "error");
return;
}
if (!newPassword) {
showMessage("Введите новый пароль", "error");
return;
}
if (newPassword.length < 6) {
showMessage("Новый пароль должен быть не менее 6 символов", "error");
return;
}
if (newPassword !== confirmPassword) {
showMessage("Новый пароль и подтверждение не совпадают", "error");
return;
}
try {
const response = await fetch("/api/user/profile", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
currentPassword,
newPassword,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Ошибка изменения пароля");
}
const result = await response.json();
// Очищаем поля паролей
currentPasswordInput.value = "";
newPasswordInput.value = "";
confirmPasswordInput.value = "";
showMessage(result.message || "Пароль успешно изменен", "success");
} catch (error) {
console.error("Ошибка изменения пароля:", error);
showMessage(error.message, "error");
}
});
// Функция валидации email
function isValidEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
// Функция для проверки аутентификации
async function checkAuthentication() {
const isAuthenticated = localStorage.getItem('isAuthenticated');
if (isAuthenticated !== 'true') {
// Если пользователь не аутентифицирован, перенаправляем на страницу входа
window.location.href = "/";
return;
}
// Проверяем, что сессия на сервере еще действительна
try {
const response = await fetch("/api/auth/status");
if (!response.ok) {
// Если сессия недействительна, очищаем localStorage и перенаправляем
localStorage.removeItem('isAuthenticated');
localStorage.removeItem('username');
window.location.href = "/";
return;
}
const authData = await response.json();
if (!authData.authenticated) {
// Если сервер говорит, что пользователь не аутентифицирован
localStorage.removeItem('isAuthenticated');
localStorage.removeItem('username');
window.location.href = "/";
return;
}
} catch (error) {
console.error("Ошибка проверки аутентификации:", error);
// В случае ошибки сети, оставляем пользователя на странице
// но показываем предупреждение
console.warn("Не удалось проверить статус аутентификации");
}
}
// Функция для настройки обработчика выхода
function setupLogoutHandler() {
const logoutForms = document.querySelectorAll('form[action="/logout"]');
logoutForms.forEach(form => {
form.addEventListener('submit', function(e) {
// Очищаем localStorage перед выходом
localStorage.removeItem('isAuthenticated');
localStorage.removeItem('username');
});
});
}
// Загружаем профиль при загрузке страницы
document.addEventListener("DOMContentLoaded", function () {
// Проверяем аутентификацию при загрузке страницы
checkAuthentication();
loadProfile();
// Добавляем обработчик для кнопки выхода
setupLogoutHandler();
});