v2.0.0: Multi-user authentication with JWT
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 16s
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 16s
Features: - User registration and login with JWT tokens - All data is now user-specific (multi-tenancy) - Profile page with integrations and logout - Automatic migration of existing data to first user Backend changes: - Added users and refresh_tokens tables - Added user_id to all data tables (projects, entries, nodes, dictionaries, words, progress, configs, telegram_integrations, weekly_goals) - JWT authentication middleware - claimOrphanedData() for data migration Frontend changes: - AuthContext for state management - Login/Register forms - Profile page (replaced Integrations) - All API calls use authFetch with Bearer token Migration notes: - On first deploy, backend automatically adds user_id columns - First user to login claims all existing data
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useAuth } from './auth/AuthContext'
|
||||
import './WordList.css'
|
||||
|
||||
const API_URL = '/api'
|
||||
|
||||
function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger = 0 }) {
|
||||
const { authFetch } = useAuth()
|
||||
const [words, setWords] = useState([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState('')
|
||||
@@ -44,7 +46,7 @@ function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger =
|
||||
|
||||
const fetchDictionary = async (dictId) => {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/dictionaries`)
|
||||
const response = await authFetch(`${API_URL}/dictionaries`)
|
||||
if (!response.ok) {
|
||||
throw new Error('Ошибка при загрузке словарей')
|
||||
}
|
||||
@@ -74,7 +76,7 @@ function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger =
|
||||
try {
|
||||
setLoading(true)
|
||||
const url = `${API_URL}/words?dictionary_id=${dictId}`
|
||||
const response = await fetch(url)
|
||||
const response = await authFetch(url)
|
||||
if (!response.ok) {
|
||||
throw new Error('Ошибка при загрузке слов')
|
||||
}
|
||||
@@ -102,7 +104,7 @@ function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger =
|
||||
try {
|
||||
if (!hasValidDictionary(currentDictionaryId)) {
|
||||
// Create new dictionary
|
||||
const response = await fetch(`${API_URL}/dictionaries`, {
|
||||
const response = await authFetch(`${API_URL}/dictionaries`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -131,7 +133,7 @@ function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger =
|
||||
onNavigate?.('words', { dictionaryId: newDictionaryId })
|
||||
} else if (hasValidDictionary(currentDictionaryId)) {
|
||||
// Update existing dictionary (rename)
|
||||
const response = await fetch(`${API_URL}/dictionaries/${currentDictionaryId}`, {
|
||||
const response = await authFetch(`${API_URL}/dictionaries/${currentDictionaryId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
Reference in New Issue
Block a user