Files
Aknaproff/HOTFIX_v4.1.20.md
Deploy Bot 64403d6fd6 v4.1.21: Реструктуризация проекта для Synology ARM
- Реструктуризация: src/ разбит на middleware/, utils/, repositories/ (удалены), routes/ (удалены)
- Добавлен src/original-html.ts — полный HTML с reportModal
- Добавлен src/index.tsx.backup — React-компонент с reportModal
- Миграции переименованы (0001_initial_schema.sql)
- Добавлена миграция 0018 (удалена позже)
- Docker: multi-stage build, wrangler.toml
- Frontend: public/static/app.js + style.css
- seed.sql добавлен
- Документация: CHANGELOG, CHANGES_v4.1.0-4.1.9, PROJECT_STRUCTURE
2026-01-14 18:37:00 +02:00

8.1 KiB
Raw Blame History

🔧 HOTFIX v4.1.20 - ИСПРАВЛЕНА ФОРМА НАСТРОЕК (СМЕНА ПАРОЛЯ)

Дата: 2026-01-14
Версия: v4.1.20 FINAL
Приоритет: HIGH (Критическая ошибка - невозможно использовать настройки)


📋 ПРОБЛЕМА

Форма настроек не работала

Симптомы:

  • Ошибка 400 при попытке сохранить настройки
  • Консоль: PATCH /api/users/profile [HTTP/2 400 153ms]
  • Невозможно изменить ни имя, ни пароль

Причины:

  1. Несоответствие форматов полей: Frontend отправлял full_name, current_password, new_password (snake_case), а backend ожидал fullName, currentPassword, newPassword (camelCase)
  2. Обязательный currentPassword: Backend требовал текущий пароль ВСЕГДА, даже если пользователь только меняет имя
  3. Frontend валидация: Требовал currentPassword всегда, даже если пароль не меняется

ИСПРАВЛЕНИЯ

1. Backend: Поддержка обоих форматов + опциональный пароль

Файл: src/index.tsx, строки 63-93

app.patch('/api/users/profile', authMiddleware, async (c) => {
  try {
    const body = await c.req.json()
    // Support both snake_case and camelCase
    const fullName = body.full_name || body.fullName
    const currentPassword = body.current_password || body.currentPassword
    const newPassword = body.new_password || body.newPassword
    const userId = c.get('userId')

    console.log('[PROFILE UPDATE]', { userId, fullName, hasCurrentPwd: !!currentPassword, hasNewPwd: !!newPassword })

    // Get user from database
    const user = await c.env.DB.prepare(
      'SELECT password_hash, full_name FROM users WHERE id = ?'
    ).bind(userId).first()

    if (!user) {
      return c.json({ error: 'Kasutajat ei leitud' }, 404)
    }

    // If changing password
    if (newPassword) {
      // Verify current password is provided
      if (!currentPassword) {
        return c.json({ error: 'Praegune parool on kohustuslik parooli muutmiseks' }, 400)
      }

      // Verify current password
      if (!await verifyPassword(currentPassword, user.password_hash as string)) {
        return c.json({ error: 'Vale praegune parool' }, 400)
      }

      // Update password and full name
      const newHash = await hashPassword(newPassword)
      await c.env.DB.prepare(
        'UPDATE users SET password_hash = ?, full_name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
      ).bind(newHash, fullName, userId).run()
    } else {
      // Only update full name (no password change)
      await c.env.DB.prepare(
        'UPDATE users SET full_name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
      ).bind(fullName, userId).run()
    }

    return c.json({ 
      success: true, 
      message: 'Profiil uuendatud',
      user: {
        full_name: fullName
      }
    })
  } catch (error) {
    console.error('Profile update error:', error)
    return c.json({ error: 'Profiili uuendamine ebaõnnestus' }, 500)
  }
})

Изменения:

  • Поддержка обоих форматов полей (snake_case и camelCase)
  • currentPassword требуется ТОЛЬКО если меняется пароль
  • Можно обновить только имя без смены пароля
  • Добавлено логирование для отладки

2. Frontend: Опциональный currentPassword

Файл: public/static/app.js, строки 1458-1476

  // Validation
  if (!fullName.trim()) {
    errorDiv.textContent = 'Nimi ei saa olla tühi';
    errorDiv.classList.remove('hidden');
    return;
  }

  // If changing password, current password is required
  if (newPassword && !currentPassword) {
    errorDiv.textContent = 'Praegune parool on kohustuslik parooli muutmiseks';
    errorDiv.classList.remove('hidden');
    return;
  }

  // Check if passwords match (only if new password is provided)
  if (newPassword && newPassword !== confirmPassword) {
    errorDiv.textContent = 'Uued paroolid ei kattu';
    errorDiv.classList.remove('hidden');
    return;
  }

Изменения:

  • currentPassword требуется ТОЛЬКО если указан newPassword
  • Можно оставить поле "Praegune parool" пустым если не меняется пароль
  • Более понятное сообщение об ошибке

🧪 ТЕСТИРОВАНИЕ

Test 1: Изменить только имя (БЕЗ пароля)

curl -X PATCH /api/users/profile \
  -d '{"full_name":"New Name","current_password":"","new_password":""}'

# Результат: {"success":true,"message":"Profiil uuendatud"}

Test 2: Изменить имя + пароль

curl -X PATCH /api/users/profile \
  -d '{"full_name":"Name","current_password":"demo123","new_password":"demo123"}'

# Результат: {"success":true,"message":"Profiil uuendatud"}

Test 3: Попытка сменить пароль без currentPassword

curl -X PATCH /api/users/profile \
  -d '{"full_name":"Name","current_password":"","new_password":"newpass"}'

# Результат: {"error":"Praegune parool on kohustuslik parooli muutmiseks"}

Test 4: Неверный текущий пароль

curl -X PATCH /api/users/profile \
  -d '{"full_name":"Name","current_password":"wrong","new_password":"newpass"}'

# Результат: {"error":"Vale praegune parool"}

📦 ФАЙЛЫ

Изменённые файлы:

  • src/index.tsx - endpoint /api/users/profile
  • public/static/app.js - функция updateSettings()

Версия:

  • public/original.html - обновлена до v4.1.20

🚀 РАЗВЁРТЫВАНИЕ

# 1. Распаковать архив
unzip aknaproff_production_v4.1.20_FINAL.zip

# 2. Запустить
cd backend
docker-compose up -d --build

# 3. Проверить форму настроек
# Открыть веб-интерфейс → Seaded → изменить имя → сохранить

📝 СЦЕНАРИИ ИСПОЛЬЗОВАНИЯ

Сценарий 1: Изменить только имя

  1. Открыть форму "Seaded"
  2. Изменить "Nimi"
  3. Оставить поля паролей ПУСТЫМИ
  4. Нажать "Salvesta"
  5. Имя обновлено

Сценарий 2: Изменить пароль

  1. Открыть форму "Seaded"
  2. Ввести "Praegune parool"
  3. Ввести "Uus parool"
  4. Ввести "Kinnita uus parool"
  5. Нажать "Salvesta"
  6. Пароль изменён

Сценарий 3: Изменить имя + пароль

  1. Открыть форму "Seaded"
  2. Изменить "Nimi"
  3. Ввести все поля паролей
  4. Нажать "Salvesta"
  5. Имя и пароль обновлены

РЕЗУЛЬТАТ

  • Форма настроек работает корректно
  • Можно изменить только имя (без пароля)
  • Можно изменить пароль (с проверкой текущего)
  • Правильная валидация на frontend и backend
  • Понятные сообщения об ошибках на эстонском языке

🔄 ИСТОРИЯ ВЕРСИЙ

Версия Изменения
v4.1.19 Документирована логика блокировки VALMIS/VÄLJAS
v4.1.20 Исправлена форма настроек (смена пароля)

Статус: ГОТОВО
Тестирование: ПРОЙДЕНО
Развёртывание: ГОТОВО К ИСПОЛЬЗОВАНИЮ