Описание изменений
This commit is contained in:
340
backend/routes/kanban.js
Normal file
340
backend/routes/kanban.js
Normal file
@@ -0,0 +1,340 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { Pool } = require('pg');
|
||||
const pool = new Pool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false
|
||||
});
|
||||
|
||||
// Middleware для проверки аутентификации
|
||||
function requireAuth(req, res, next) {
|
||||
if (!req.session || (!req.session.isAuthenticated && !req.session.authenticated)) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
// Получение всех досок пользователя
|
||||
router.get('/boards', async (req, res) => {
|
||||
try {
|
||||
// Для разработки: если сессия не содержит адрес, используем тестовый
|
||||
const userAddress = (req.session.address || '0xf45aa4917b3775ba37f48aeb3dc1a943561e9e0b').toLowerCase();
|
||||
|
||||
console.log('Запрос досок для адреса:', userAddress);
|
||||
|
||||
// Проверяем, существует ли пользователь
|
||||
const userResult = await pool.query(
|
||||
'SELECT id FROM users WHERE address = $1',
|
||||
[userAddress]
|
||||
);
|
||||
|
||||
console.log('Результат запроса пользователя:', userResult.rows);
|
||||
|
||||
if (userResult.rows.length === 0) {
|
||||
console.log('Пользователь не найден, создаем нового');
|
||||
// Если пользователь не найден, создаем его
|
||||
const newUserResult = await pool.query(
|
||||
'INSERT INTO users (address, created_at) VALUES ($1, NOW()) RETURNING id',
|
||||
[userAddress]
|
||||
);
|
||||
console.log('Создан новый пользователь:', newUserResult.rows);
|
||||
}
|
||||
|
||||
// Получаем доски пользователя
|
||||
const ownBoardsQuery = 'SELECT kb.* FROM kanban_boards kb ' +
|
||||
'JOIN users u ON kb.owner_id = u.id ' +
|
||||
'WHERE u.address = $1 ' +
|
||||
'ORDER BY kb.updated_at DESC';
|
||||
|
||||
console.log('Запрос досок пользователя:', ownBoardsQuery);
|
||||
|
||||
const ownBoardsResult = await pool.query(ownBoardsQuery, [userAddress]);
|
||||
|
||||
console.log('Результат запроса досок пользователя:', ownBoardsResult.rows);
|
||||
|
||||
// Получаем доски, к которым у пользователя есть доступ
|
||||
const sharedBoardsResult = await pool.query(
|
||||
'SELECT kb.* FROM kanban_boards kb ' +
|
||||
'JOIN kanban_board_access kba ON kb.id = kba.board_id ' +
|
||||
'JOIN users u1 ON kba.user_id = u1.id ' +
|
||||
'JOIN users u2 ON kb.owner_id = u2.id ' +
|
||||
'WHERE u1.address = $1 AND u2.address != $1 ' +
|
||||
'ORDER BY kb.updated_at DESC',
|
||||
[userAddress]
|
||||
);
|
||||
|
||||
// Получаем публичные доски
|
||||
const publicBoardsResult = await pool.query(
|
||||
'SELECT kb.* FROM kanban_boards kb ' +
|
||||
'JOIN users u ON kb.owner_id = u.id ' +
|
||||
'WHERE kb.is_public = true AND u.address != $1 ' +
|
||||
'AND NOT EXISTS (' +
|
||||
' SELECT 1 FROM kanban_board_access kba ' +
|
||||
' JOIN users u2 ON kba.user_id = u2.id ' +
|
||||
' WHERE kba.board_id = kb.id AND u2.address = $1' +
|
||||
') ' +
|
||||
'ORDER BY kb.updated_at DESC',
|
||||
[userAddress]
|
||||
);
|
||||
|
||||
res.json({
|
||||
ownBoards: ownBoardsResult.rows,
|
||||
sharedBoards: sharedBoardsResult.rows,
|
||||
publicBoards: publicBoardsResult.rows
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching boards:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Создание новой доски
|
||||
router.post('/boards', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { title, description, isPublic } = req.body;
|
||||
|
||||
// Получаем ID пользователя
|
||||
let userResult = await pool.query(
|
||||
'SELECT id FROM users WHERE address = $1',
|
||||
[req.session.address]
|
||||
);
|
||||
|
||||
let userId;
|
||||
|
||||
if (userResult.rows.length === 0) {
|
||||
// Если пользователь не найден, создаем его
|
||||
const newUserResult = await pool.query(
|
||||
'INSERT INTO users (address, created_at, preferred_language) VALUES ($1, NOW(), $2) RETURNING id',
|
||||
[req.session.address, 'ru']
|
||||
);
|
||||
|
||||
userId = newUserResult.rows[0].id;
|
||||
} else {
|
||||
userId = userResult.rows[0].id;
|
||||
}
|
||||
|
||||
// Создаем новую доску
|
||||
const result = await pool.query(
|
||||
`INSERT INTO kanban_boards (title, description, owner_id, is_public, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, NOW(), NOW())
|
||||
RETURNING *`,
|
||||
[title, description, userId, isPublic]
|
||||
);
|
||||
|
||||
// Создаем стандартные колонки
|
||||
const columns = ['Backlog', 'In Progress', 'Review', 'Done'];
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
await pool.query(
|
||||
`INSERT INTO kanban_columns (board_id, title, position, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, NOW(), NOW())`,
|
||||
[result.rows[0].id, columns[i], i]
|
||||
);
|
||||
}
|
||||
|
||||
res.status(201).json(result.rows[0]);
|
||||
} catch (error) {
|
||||
console.error('Error creating kanban board:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Получение конкретной доски со всеми колонками и карточками
|
||||
router.get('/boards/:id', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const boardId = req.params.id;
|
||||
|
||||
// Получаем ID пользователя
|
||||
let userResult = await pool.query(
|
||||
'SELECT id FROM users WHERE address = $1',
|
||||
[req.session.address]
|
||||
);
|
||||
|
||||
let userId;
|
||||
|
||||
if (userResult.rows.length === 0) {
|
||||
// Если пользователь не найден, создаем его
|
||||
const newUserResult = await pool.query(
|
||||
'INSERT INTO users (address, created_at, preferred_language) VALUES ($1, NOW(), $2) RETURNING id',
|
||||
[req.session.address, 'ru']
|
||||
);
|
||||
|
||||
userId = newUserResult.rows[0].id;
|
||||
} else {
|
||||
userId = userResult.rows[0].id;
|
||||
}
|
||||
|
||||
// Проверяем доступ к доске
|
||||
const boardResult = await pool.query(
|
||||
'SELECT * FROM kanban_boards WHERE id = $1',
|
||||
[boardId]
|
||||
);
|
||||
|
||||
if (boardResult.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'Board not found' });
|
||||
}
|
||||
|
||||
const board = boardResult.rows[0];
|
||||
|
||||
// Проверяем, имеет ли пользователь доступ к доске
|
||||
if (board.owner_id !== userId && !board.is_public) {
|
||||
const accessResult = await pool.query(
|
||||
'SELECT * FROM kanban_board_access WHERE board_id = $1 AND user_id = $2',
|
||||
[boardId, userId]
|
||||
);
|
||||
|
||||
if (accessResult.rows.length === 0) {
|
||||
return res.status(403).json({ error: 'Access denied' });
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем колонки доски
|
||||
const columnsResult = await pool.query(
|
||||
'SELECT * FROM kanban_columns WHERE board_id = $1 ORDER BY position',
|
||||
[boardId]
|
||||
);
|
||||
|
||||
// Получаем карточки для всех колонок
|
||||
const cardsResult = await pool.query(
|
||||
`SELECT kc.*, u.address as assigned_address
|
||||
FROM kanban_cards kc
|
||||
LEFT JOIN users u ON kc.assigned_to = u.id
|
||||
WHERE kc.column_id IN (
|
||||
SELECT id FROM kanban_columns WHERE board_id = $1
|
||||
)
|
||||
ORDER BY kc.position`,
|
||||
[boardId]
|
||||
);
|
||||
|
||||
// Группируем карточки по колонкам
|
||||
const columns = columnsResult.rows.map(column => {
|
||||
const cards = cardsResult.rows.filter(card => card.column_id === column.id);
|
||||
return {
|
||||
...column,
|
||||
cards
|
||||
};
|
||||
});
|
||||
|
||||
res.json({
|
||||
...board,
|
||||
columns
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error getting kanban board:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Добавление колонки к доске
|
||||
router.post('/boards/:boardId/columns', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { boardId } = req.params;
|
||||
const { title, wipLimit } = req.body;
|
||||
|
||||
// Проверяем, существует ли доска
|
||||
const boardResult = await pool.query(
|
||||
'SELECT * FROM kanban_boards WHERE id = $1',
|
||||
[boardId]
|
||||
);
|
||||
|
||||
if (boardResult.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'Board not found' });
|
||||
}
|
||||
|
||||
// Получаем максимальную позицию колонок
|
||||
const positionResult = await pool.query(
|
||||
'SELECT MAX(position) as max_position FROM kanban_columns WHERE board_id = $1',
|
||||
[boardId]
|
||||
);
|
||||
|
||||
const position = positionResult.rows[0].max_position ? positionResult.rows[0].max_position + 1 : 0;
|
||||
|
||||
// Создаем новую колонку
|
||||
const result = await pool.query(
|
||||
`INSERT INTO kanban_columns (board_id, title, position, wip_limit, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, NOW(), NOW())
|
||||
RETURNING *`,
|
||||
[boardId, title, position, wipLimit]
|
||||
);
|
||||
|
||||
res.status(201).json(result.rows[0]);
|
||||
} catch (error) {
|
||||
console.error('Error creating column:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Получение колонок доски
|
||||
router.get('/boards/:boardId/columns', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { boardId } = req.params;
|
||||
|
||||
const result = await pool.query(
|
||||
'SELECT * FROM kanban_columns WHERE board_id = $1 ORDER BY position',
|
||||
[boardId]
|
||||
);
|
||||
|
||||
res.json(result.rows);
|
||||
} catch (error) {
|
||||
console.error('Error getting columns:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Создание карточки
|
||||
router.post('/cards', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { title, description, columnId, dueDate } = req.body;
|
||||
|
||||
// Получаем ID пользователя
|
||||
let userResult = await pool.query(
|
||||
'SELECT id FROM users WHERE address = $1',
|
||||
[req.session.address]
|
||||
);
|
||||
|
||||
let userId;
|
||||
|
||||
if (userResult.rows.length === 0) {
|
||||
// Если пользователь не найден, создаем его
|
||||
const newUserResult = await pool.query(
|
||||
'INSERT INTO users (address, created_at, preferred_language) VALUES ($1, NOW(), $2) RETURNING id',
|
||||
[req.session.address, 'ru']
|
||||
);
|
||||
|
||||
userId = newUserResult.rows[0].id;
|
||||
} else {
|
||||
userId = userResult.rows[0].id;
|
||||
}
|
||||
|
||||
// Получаем максимальную позицию карточек в колонке
|
||||
const positionResult = await pool.query(
|
||||
'SELECT MAX(position) as max_position FROM kanban_cards WHERE column_id = $1',
|
||||
[columnId]
|
||||
);
|
||||
|
||||
const position = positionResult.rows[0].max_position ? positionResult.rows[0].max_position + 1 : 0;
|
||||
|
||||
// Создаем новую карточку
|
||||
const result = await pool.query(
|
||||
`INSERT INTO kanban_cards (column_id, title, description, position, due_date, created_by, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
|
||||
RETURNING *`,
|
||||
[columnId, title, description, position, dueDate, userId]
|
||||
);
|
||||
|
||||
// Получаем информацию о пользователе для отображения
|
||||
const cardWithUser = {
|
||||
...result.rows[0],
|
||||
assigned_address: null
|
||||
};
|
||||
|
||||
res.status(201).json(cardWithUser);
|
||||
} catch (error) {
|
||||
console.error('Error creating card:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Добавляем остальные маршруты для работы с колонками, карточками и т.д.
|
||||
// ...
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user