1015 lines
42 KiB
JavaScript
1015 lines
42 KiB
JavaScript
// api2-groups.js
|
||
// API для управления внешними идентификаторами пользователей
|
||
|
||
const express = require('express');
|
||
const router = express.Router();
|
||
|
||
module.exports = function(app, db) {
|
||
|
||
// Middleware для проверки аутентификации
|
||
const requireAuth = (req, res, next) => {
|
||
if (!req.session || !req.session.user) {
|
||
return res.status(401).json({ error: 'Требуется аутентификация' });
|
||
}
|
||
next();
|
||
};
|
||
|
||
// Middleware для проверки прав администратора
|
||
const requireAdmin = (req, res, next) => {
|
||
if (!req.session || !req.session.user || req.session.user.role !== 'admin') {
|
||
return res.status(403).json({ error: 'Недостаточно прав' });
|
||
}
|
||
next();
|
||
};
|
||
|
||
// 1. Создание таблиц при инициализации
|
||
function createIdTables() {
|
||
return new Promise((resolve, reject) => {
|
||
// Таблица с группами для идентификаторов
|
||
db.run(`
|
||
CREATE TABLE IF NOT EXISTS idgroups (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
name TEXT NOT NULL UNIQUE,
|
||
description TEXT,
|
||
service_type TEXT NOT NULL, -- 'sberbank', 'yandex', 'ldap', 'other'
|
||
is_active BOOLEAN DEFAULT true,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||
)
|
||
`, (err) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка создания таблицы idgroups:', err.message);
|
||
reject(err);
|
||
return;
|
||
}
|
||
|
||
// Таблица с идентификаторами пользователей
|
||
db.run(`
|
||
CREATE TABLE IF NOT EXISTS idusers (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
user_id INTEGER NOT NULL,
|
||
service_type TEXT NOT NULL, -- 'sberbank', 'yandex', 'ldap', 'other'
|
||
external_id TEXT, -- СДЕЛАЛИ НЕОБЯЗАТЕЛЬНЫМ
|
||
login TEXT, -- Логин LDAP (если есть)
|
||
ldap_group TEXT, -- Группа LDAP (если есть)
|
||
group_id INTEGER, -- Ссылка на группу в idgroups
|
||
metadata TEXT, -- Дополнительные данные в JSON
|
||
is_active BOOLEAN DEFAULT true,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
|
||
FOREIGN KEY (group_id) REFERENCES idgroups (id) ON DELETE SET NULL,
|
||
UNIQUE(user_id, service_type, external_id) -- Теперь external_id может быть NULL
|
||
)
|
||
`, (err) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка создания таблицы idusers:', err.message);
|
||
reject(err);
|
||
return;
|
||
}
|
||
|
||
// Создаем индексы
|
||
db.run('CREATE INDEX IF NOT EXISTS idx_idusers_user_id ON idusers(user_id)', (err) => {
|
||
if (err) console.error('❌ Ошибка создания индекса idx_idusers_user_id:', err.message);
|
||
});
|
||
|
||
db.run('CREATE INDEX IF NOT EXISTS idx_idusers_service_type ON idusers(service_type)', (err) => {
|
||
if (err) console.error('❌ Ошибка создания индекса idx_idusers_service_type:', err.message);
|
||
});
|
||
|
||
db.run('CREATE INDEX IF NOT EXISTS idx_idusers_external_id ON idusers(external_id)', (err) => {
|
||
if (err) console.error('❌ Ошибка создания индекса idx_idusers_external_id:', err.message);
|
||
});
|
||
|
||
db.run('CREATE INDEX IF NOT EXISTS idx_idgroups_service_type ON idgroups(service_type)', (err) => {
|
||
if (err) console.error('❌ Ошибка создания индекса idx_idgroups_service_type:', err.message);
|
||
});
|
||
|
||
console.log('✅ Таблицы для внешних идентификаторов созданы');
|
||
resolve();
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
// 2. Добавление стандартных групп
|
||
function addDefaultGroups() {
|
||
const defaultGroups = [
|
||
{
|
||
name: 'Сбербанк',
|
||
description: 'Идентификаторы в системе Сбербанка',
|
||
service_type: 'sberbank',
|
||
is_active: true
|
||
},
|
||
{
|
||
name: 'Яндекс',
|
||
description: 'Идентификаторы в системе Яндекса',
|
||
service_type: 'yandex',
|
||
is_active: true
|
||
},
|
||
{
|
||
name: 'LDAP - Преподаватели',
|
||
description: 'Пользователи из LDAP с ролью преподавателя',
|
||
service_type: 'ldap',
|
||
is_active: true
|
||
},
|
||
{
|
||
name: 'LDAP - Администрация',
|
||
description: 'Пользователи из LDAP в группе Администрация',
|
||
service_type: 'ldap',
|
||
is_active: true
|
||
},
|
||
{
|
||
name: 'LDAP - Руководство',
|
||
description: 'Руководители',
|
||
service_type: 'ldap',
|
||
is_active: true
|
||
},
|
||
{
|
||
name: 'Прочие системы',
|
||
description: 'Идентификаторы из других систем',
|
||
service_type: 'other',
|
||
is_active: true
|
||
}
|
||
];
|
||
|
||
defaultGroups.forEach(group => {
|
||
db.get("SELECT id FROM idgroups WHERE name = ?", [group.name], (err, existing) => {
|
||
if (err) {
|
||
console.error(`❌ Ошибка проверки группы ${group.name}:`, err.message);
|
||
return;
|
||
}
|
||
|
||
if (!existing) {
|
||
db.run(
|
||
`INSERT INTO idgroups (name, description, service_type, is_active)
|
||
VALUES (?, ?, ?, ?)`,
|
||
[group.name, group.description, group.service_type, group.is_active ? 1 : 0],
|
||
(insertErr) => {
|
||
if (insertErr) {
|
||
console.error(`❌ Ошибка создания группы ${group.name}:`, insertErr.message);
|
||
} else {
|
||
console.log(`✅ Группа "${group.name}" создана по умолчанию`);
|
||
}
|
||
}
|
||
);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// 3. API эндпоинты
|
||
|
||
// GET /api2/groups - Получить все группы (доступно всем аутентифицированным)
|
||
router.get('/api2/groups', requireAuth, (req, res) => {
|
||
const { service_type, is_active } = req.query;
|
||
|
||
let query = 'SELECT * FROM idgroups WHERE 1=1';
|
||
const params = [];
|
||
|
||
if (service_type) {
|
||
query += ' AND service_type = ?';
|
||
params.push(service_type);
|
||
}
|
||
|
||
if (is_active !== undefined) {
|
||
query += ' AND is_active = ?';
|
||
params.push(is_active === 'true' ? 1 : 0);
|
||
}
|
||
|
||
query += ' ORDER BY service_type, name';
|
||
|
||
db.all(query, params, (err, groups) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения групп:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения групп' });
|
||
}
|
||
res.json(groups || []);
|
||
});
|
||
});
|
||
|
||
// GET /api2/groups/:id - Получить группу по ID (доступно всем аутентифицированным)
|
||
router.get('/api2/groups/:id', requireAuth, (req, res) => {
|
||
const { id } = req.params;
|
||
|
||
db.get('SELECT * FROM idgroups WHERE id = ?', [id], (err, group) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения группы' });
|
||
}
|
||
|
||
if (!group) {
|
||
return res.status(404).json({ error: 'Группа не найдена' });
|
||
}
|
||
|
||
res.json(group);
|
||
});
|
||
});
|
||
|
||
// POST /api2/groups - Создать новую группу (только админ)
|
||
router.post('/api2/groups', requireAuth, requireAdmin, (req, res) => {
|
||
const { name, description, service_type, is_active } = req.body;
|
||
|
||
if (!name || !service_type) {
|
||
return res.status(400).json({
|
||
error: 'Обязательные поля: name, service_type'
|
||
});
|
||
}
|
||
|
||
const validServiceTypes = ['sberbank', 'yandex', 'ldap', 'other'];
|
||
if (!validServiceTypes.includes(service_type)) {
|
||
return res.status(400).json({
|
||
error: `Недопустимый тип сервиса. Допустимые значения: ${validServiceTypes.join(', ')}`
|
||
});
|
||
}
|
||
|
||
db.run(
|
||
`INSERT INTO idgroups (name, description, service_type, is_active)
|
||
VALUES (?, ?, ?, ?)`,
|
||
[
|
||
name,
|
||
description || '',
|
||
service_type,
|
||
is_active !== undefined ? (is_active ? 1 : 0) : 1
|
||
],
|
||
function(err) {
|
||
if (err) {
|
||
if (err.code === 'SQLITE_CONSTRAINT') {
|
||
return res.status(409).json({ error: 'Группа с таким именем уже существует' });
|
||
}
|
||
console.error('❌ Ошибка создания группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка создания группы' });
|
||
}
|
||
|
||
res.status(201).json({
|
||
success: true,
|
||
id: this.lastID,
|
||
message: 'Группа успешно создана'
|
||
});
|
||
}
|
||
);
|
||
});
|
||
|
||
// PUT /api2/groups/:id - Обновить группу (только админ)
|
||
router.put('/api2/groups/:id', requireAuth, requireAdmin, (req, res) => {
|
||
const { id } = req.params;
|
||
const { name, description, service_type, is_active } = req.body;
|
||
|
||
// Проверяем существование группы
|
||
db.get('SELECT id FROM idgroups WHERE id = ?', [id], (err, existing) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка проверки группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка проверки группы' });
|
||
}
|
||
|
||
if (!existing) {
|
||
return res.status(404).json({ error: 'Группа не найдена' });
|
||
}
|
||
|
||
// Собираем поля для обновления
|
||
const updates = [];
|
||
const params = [];
|
||
|
||
if (name !== undefined) {
|
||
updates.push('name = ?');
|
||
params.push(name);
|
||
}
|
||
|
||
if (description !== undefined) {
|
||
updates.push('description = ?');
|
||
params.push(description);
|
||
}
|
||
|
||
if (service_type !== undefined) {
|
||
const validServiceTypes = ['sberbank', 'yandex', 'ldap', 'other'];
|
||
if (!validServiceTypes.includes(service_type)) {
|
||
return res.status(400).json({
|
||
error: `Недопустимый тип сервиса. Допустимые значения: ${validServiceTypes.join(', ')}`
|
||
});
|
||
}
|
||
updates.push('service_type = ?');
|
||
params.push(service_type);
|
||
}
|
||
|
||
if (is_active !== undefined) {
|
||
updates.push('is_active = ?');
|
||
params.push(is_active ? 1 : 0);
|
||
}
|
||
|
||
if (updates.length === 0) {
|
||
return res.status(400).json({ error: 'Нет данных для обновления' });
|
||
}
|
||
|
||
updates.push('updated_at = CURRENT_TIMESTAMP');
|
||
params.push(id);
|
||
|
||
const query = `UPDATE idgroups SET ${updates.join(', ')} WHERE id = ?`;
|
||
|
||
db.run(query, params, function(err) {
|
||
if (err) {
|
||
if (err.code === 'SQLITE_CONSTRAINT') {
|
||
return res.status(409).json({ error: 'Группа с таким именем уже существует' });
|
||
}
|
||
console.error('❌ Ошибка обновления группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка обновления группы' });
|
||
}
|
||
|
||
res.json({
|
||
success: true,
|
||
changes: this.changes,
|
||
message: 'Группа успешно обновлена'
|
||
});
|
||
});
|
||
});
|
||
});
|
||
|
||
// DELETE /api2/groups/:id - Удалить группу (только админ)
|
||
router.delete('/api2/groups/:id', requireAuth, requireAdmin, (req, res) => {
|
||
const { id } = req.params;
|
||
|
||
// Проверяем, используется ли группа
|
||
db.get('SELECT COUNT(*) as count FROM idusers WHERE group_id = ?', [id], (err, result) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка проверки использования группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка проверки группы' });
|
||
}
|
||
|
||
if (result.count > 0) {
|
||
return res.status(400).json({
|
||
error: 'Невозможно удалить группу, так как она используется в идентификаторах пользователей',
|
||
used_count: result.count
|
||
});
|
||
}
|
||
|
||
db.run('DELETE FROM idgroups WHERE id = ?', [id], function(err) {
|
||
if (err) {
|
||
console.error('❌ Ошибка удаления группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка удаления группы' });
|
||
}
|
||
|
||
res.json({
|
||
success: true,
|
||
changes: this.changes,
|
||
message: 'Группа успешно удалена'
|
||
});
|
||
});
|
||
});
|
||
});
|
||
|
||
// GET /api2/idusers - Получить все идентификаторы пользователей (доступно всем аутентифицированным)
|
||
router.get('/api2/idusers', requireAuth, (req, res) => {
|
||
const { user_id, service_type, external_id, group_id, is_active } = req.query;
|
||
|
||
let query = `
|
||
SELECT iu.*,
|
||
u.name as user_name,
|
||
u.login as user_login,
|
||
u.email as user_email,
|
||
g.name as group_name
|
||
FROM idusers iu
|
||
LEFT JOIN users u ON iu.user_id = u.id
|
||
LEFT JOIN idgroups g ON iu.group_id = g.id
|
||
WHERE 1=1
|
||
`;
|
||
|
||
const params = [];
|
||
|
||
if (user_id) {
|
||
query += ' AND iu.user_id = ?';
|
||
params.push(user_id);
|
||
}
|
||
|
||
if (service_type) {
|
||
query += ' AND iu.service_type = ?';
|
||
params.push(service_type);
|
||
}
|
||
|
||
if (external_id) {
|
||
query += ' AND iu.external_id LIKE ?';
|
||
params.push(`%${external_id}%`);
|
||
}
|
||
|
||
if (group_id) {
|
||
query += ' AND iu.group_id = ?';
|
||
params.push(group_id);
|
||
}
|
||
|
||
if (is_active !== undefined) {
|
||
query += ' AND iu.is_active = ?';
|
||
params.push(is_active === 'true' ? 1 : 0);
|
||
}
|
||
|
||
query += ' ORDER BY iu.service_type, iu.external_id';
|
||
|
||
db.all(query, params, (err, idusers) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения идентификаторов пользователей:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения данных' });
|
||
}
|
||
|
||
// Парсим JSON metadata если есть
|
||
const result = (idusers || []).map(item => {
|
||
if (item.metadata) {
|
||
try {
|
||
item.metadata = JSON.parse(item.metadata);
|
||
} catch (e) {
|
||
item.metadata = {};
|
||
}
|
||
} else {
|
||
item.metadata = {};
|
||
}
|
||
return item;
|
||
});
|
||
|
||
res.json(result);
|
||
});
|
||
});
|
||
|
||
// GET /api2/idusers/:id - Получить идентификатор по ID (доступно всем аутентифицированным)
|
||
router.get('/api2/idusers/:id', requireAuth, (req, res) => {
|
||
const { id } = req.params;
|
||
|
||
db.get(`
|
||
SELECT iu.*,
|
||
u.name as user_name,
|
||
u.login as user_login,
|
||
u.email as user_email,
|
||
g.name as group_name
|
||
FROM idusers iu
|
||
LEFT JOIN users u ON iu.user_id = u.id
|
||
LEFT JOIN idgroups g ON iu.group_id = g.id
|
||
WHERE iu.id = ?
|
||
`, [id], (err, iduser) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения идентификатора:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения данных' });
|
||
}
|
||
|
||
if (!iduser) {
|
||
return res.status(404).json({ error: 'Идентификатор не найден' });
|
||
}
|
||
|
||
// Парсим JSON metadata если есть
|
||
if (iduser.metadata) {
|
||
try {
|
||
iduser.metadata = JSON.parse(iduser.metadata);
|
||
} catch (e) {
|
||
iduser.metadata = {};
|
||
}
|
||
} else {
|
||
iduser.metadata = {};
|
||
}
|
||
|
||
res.json(iduser);
|
||
});
|
||
});
|
||
|
||
// GET /api2/idusers/user/:userId - Получить идентификаторы конкретного пользователя (доступно всем аутентифицированным)
|
||
router.get('/api2/idusers/user/:userId', requireAuth, (req, res) => {
|
||
const { userId } = req.params;
|
||
const { service_type } = req.query;
|
||
|
||
let query = `
|
||
SELECT iu.*, g.name as group_name
|
||
FROM idusers iu
|
||
LEFT JOIN idgroups g ON iu.group_id = g.id
|
||
WHERE iu.user_id = ?
|
||
`;
|
||
|
||
const params = [userId];
|
||
|
||
if (service_type) {
|
||
query += ' AND iu.service_type = ?';
|
||
params.push(service_type);
|
||
}
|
||
|
||
query += ' ORDER BY iu.service_type, iu.external_id';
|
||
|
||
db.all(query, params, (err, idusers) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения идентификаторов пользователя:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения данных' });
|
||
}
|
||
|
||
// Парсим JSON metadata если есть
|
||
const result = (idusers || []).map(item => {
|
||
if (item.metadata) {
|
||
try {
|
||
item.metadata = JSON.parse(item.metadata);
|
||
} catch (e) {
|
||
item.metadata = {};
|
||
}
|
||
} else {
|
||
item.metadata = {};
|
||
}
|
||
return item;
|
||
});
|
||
|
||
res.json(result);
|
||
});
|
||
});
|
||
// GET /api2/idusers/:userId/groups - Получить группы, в которых состоит пользователь
|
||
router.get('/api2/idusers/user/:userId/groups', requireAuth, (req, res) => {
|
||
const { userId } = req.params;
|
||
|
||
const query = `
|
||
SELECT DISTINCT
|
||
g.name
|
||
FROM idgroups g
|
||
INNER JOIN idusers iu ON g.id = iu.group_id
|
||
WHERE iu.user_id = ? AND iu.is_active = 1 AND g.is_active = 1
|
||
ORDER BY g.name
|
||
`;
|
||
|
||
db.all(query, [userId], (err, results) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения групп пользователя:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения групп пользователя' });
|
||
}
|
||
|
||
// Извлекаем только имена из результатов
|
||
const groupNames = results.map(row => row.name);
|
||
|
||
res.json(groupNames || []);
|
||
});
|
||
});
|
||
|
||
// POST /api2/idusers - Создать новый идентификатор пользователя (только админ)
|
||
router.post('/api2/idusers', requireAuth, requireAdmin, (req, res) => {
|
||
const {
|
||
user_id,
|
||
service_type,
|
||
external_id,
|
||
login,
|
||
ldap_group,
|
||
group_id,
|
||
metadata,
|
||
is_active
|
||
} = req.body;
|
||
|
||
// Валидация обязательных полей - СДЕЛАЕМ external_id НЕОБЯЗАТЕЛЬНЫМ
|
||
if (!user_id || !service_type) {
|
||
return res.status(400).json({
|
||
error: 'Обязательные поля: user_id, service_type'
|
||
});
|
||
}
|
||
|
||
const validServiceTypes = ['sberbank', 'yandex', 'ldap', 'other'];
|
||
if (!validServiceTypes.includes(service_type)) {
|
||
return res.status(400).json({
|
||
error: `Недопустимый тип сервиса. Допустимые значения: ${validServiceTypes.join(', ')}`
|
||
});
|
||
}
|
||
|
||
// Проверяем существование пользователя
|
||
db.get('SELECT id FROM users WHERE id = ?', [user_id], (err, user) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка проверки пользователя:', err);
|
||
return res.status(500).json({ error: 'Ошибка проверки пользователя' });
|
||
}
|
||
|
||
if (!user) {
|
||
return res.status(404).json({ error: 'Пользователь не найден' });
|
||
}
|
||
|
||
// Если указана группа, проверяем ее существование
|
||
if (group_id) {
|
||
db.get('SELECT id, service_type FROM idgroups WHERE id = ?', [group_id], (err, group) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка проверки группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка проверки группы' });
|
||
}
|
||
|
||
if (!group) {
|
||
return res.status(404).json({ error: 'Указанная группа не найдена' });
|
||
}
|
||
|
||
// УБИРАЕМ проверку соответствия типа сервиса
|
||
// Теперь группы независимы от сервиса
|
||
createIdUser();
|
||
});
|
||
} else {
|
||
// Создаем идентификатор без группы
|
||
createIdUser();
|
||
}
|
||
|
||
function createIdUser() {
|
||
const metadataJson = metadata ? JSON.stringify(metadata) : null;
|
||
|
||
// Генерируем уникальный external_id если он не предоставлен
|
||
const finalExternalId = external_id || `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||
|
||
db.run(
|
||
`INSERT INTO idusers
|
||
(user_id, service_type, external_id, login, ldap_group, group_id, metadata, is_active)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||
[
|
||
user_id,
|
||
service_type,
|
||
finalExternalId,
|
||
login || null,
|
||
ldap_group || null,
|
||
group_id || null,
|
||
metadataJson,
|
||
is_active !== undefined ? (is_active ? 1 : 0) : 1
|
||
],
|
||
function(err) {
|
||
if (err) {
|
||
if (err.code === 'SQLITE_CONSTRAINT') {
|
||
return res.status(409).json({
|
||
error: 'Идентификатор с такими параметрами уже существует для этого пользователя'
|
||
});
|
||
}
|
||
console.error('❌ Ошибка создания идентификатора:', err);
|
||
return res.status(500).json({ error: 'Ошибка создания идентификатора' });
|
||
}
|
||
|
||
res.status(201).json({
|
||
success: true,
|
||
id: this.lastID,
|
||
message: 'Идентификатор успешно создан'
|
||
});
|
||
}
|
||
);
|
||
}
|
||
});
|
||
});
|
||
|
||
// PUT /api2/idusers/:id - Обновить идентификатор пользователя (только админ)
|
||
router.put('/api2/idusers/:id', requireAuth, requireAdmin, (req, res) => {
|
||
const { id } = req.params;
|
||
const {
|
||
user_id,
|
||
service_type,
|
||
external_id,
|
||
login,
|
||
ldap_group,
|
||
group_id,
|
||
metadata,
|
||
is_active
|
||
} = req.body;
|
||
|
||
// Проверяем существование идентификатора
|
||
db.get('SELECT * FROM idusers WHERE id = ?', [id], (err, existing) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка проверки идентификатора:', err);
|
||
return res.status(500).json({ error: 'Ошибка проверки идентификатора' });
|
||
}
|
||
|
||
if (!existing) {
|
||
return res.status(404).json({ error: 'Идентификатор не найден' });
|
||
}
|
||
|
||
// Если указана группа и она меняется, проверяем существование новой группы
|
||
if (group_id !== undefined && group_id !== existing.group_id) {
|
||
if (group_id) {
|
||
db.get('SELECT id FROM idgroups WHERE id = ?', [group_id], (err, group) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка проверки группы:', err);
|
||
return res.status(500).json({ error: 'Ошибка проверки группы' });
|
||
}
|
||
|
||
if (!group) {
|
||
return res.status(404).json({ error: 'Указанная группа не найдена' });
|
||
}
|
||
|
||
// УБИРАЕМ проверку соответствия типа сервиса
|
||
// Теперь группы независимы от сервиса
|
||
updateIdUser();
|
||
});
|
||
} else {
|
||
updateIdUser();
|
||
}
|
||
} else {
|
||
updateIdUser();
|
||
}
|
||
|
||
function updateIdUser() {
|
||
// Собираем поля для обновления
|
||
const updates = [];
|
||
const params = [];
|
||
|
||
if (user_id !== undefined) {
|
||
updates.push('user_id = ?');
|
||
params.push(user_id);
|
||
}
|
||
|
||
if (service_type !== undefined) {
|
||
const validServiceTypes = ['sberbank', 'yandex', 'ldap', 'other'];
|
||
if (!validServiceTypes.includes(service_type)) {
|
||
return res.status(400).json({
|
||
error: `Недопустимый тип сервиса. Допустимые значения: ${validServiceTypes.join(', ')}`
|
||
});
|
||
}
|
||
updates.push('service_type = ?');
|
||
params.push(service_type);
|
||
}
|
||
|
||
if (external_id !== undefined) {
|
||
updates.push('external_id = ?');
|
||
// Генерируем временный external_id если он пустой
|
||
const finalExternalId = external_id || `temp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||
params.push(finalExternalId);
|
||
}
|
||
|
||
if (login !== undefined) {
|
||
updates.push('login = ?');
|
||
params.push(login || null);
|
||
}
|
||
|
||
if (ldap_group !== undefined) {
|
||
updates.push('ldap_group = ?');
|
||
params.push(ldap_group || null);
|
||
}
|
||
|
||
if (group_id !== undefined) {
|
||
updates.push('group_id = ?');
|
||
params.push(group_id || null);
|
||
}
|
||
|
||
if (metadata !== undefined) {
|
||
updates.push('metadata = ?');
|
||
params.push(metadata ? JSON.stringify(metadata) : null);
|
||
}
|
||
|
||
if (is_active !== undefined) {
|
||
updates.push('is_active = ?');
|
||
params.push(is_active ? 1 : 0);
|
||
}
|
||
|
||
if (updates.length === 0) {
|
||
return res.status(400).json({ error: 'Нет данных для обновления' });
|
||
}
|
||
|
||
updates.push('updated_at = CURRENT_TIMESTAMP');
|
||
params.push(id);
|
||
|
||
const query = `UPDATE idusers SET ${updates.join(', ')} WHERE id = ?`;
|
||
|
||
db.run(query, params, function(err) {
|
||
if (err) {
|
||
if (err.code === 'SQLITE_CONSTRAINT') {
|
||
return res.status(409).json({
|
||
error: 'Идентификатор с такими параметрами уже существует'
|
||
});
|
||
}
|
||
console.error('❌ Ошибка обновления идентификатора:', err);
|
||
return res.status(500).json({ error: 'Ошибка обновления идентификатора' });
|
||
}
|
||
|
||
res.json({
|
||
success: true,
|
||
changes: this.changes,
|
||
message: 'Идентификатор успешно обновлен'
|
||
});
|
||
});
|
||
}
|
||
});
|
||
});
|
||
|
||
// DELETE /api2/idusers/:id - Удалить идентификатор пользователя (только админ)
|
||
router.delete('/api2/idusers/:id', requireAuth, requireAdmin, (req, res) => {
|
||
const { id } = req.params;
|
||
|
||
db.run('DELETE FROM idusers WHERE id = ?', [id], function(err) {
|
||
if (err) {
|
||
console.error('❌ Ошибка удаления идентификатора:', err);
|
||
return res.status(500).json({ error: 'Ошибка удаления идентификатора' });
|
||
}
|
||
|
||
res.json({
|
||
success: true,
|
||
changes: this.changes,
|
||
message: 'Идентификатор успешно удален'
|
||
});
|
||
});
|
||
});
|
||
|
||
// GET /api2/idusers/search - Поиск идентификаторов (доступно всем аутентифицированным)
|
||
router.get('/api2/idusers/search', requireAuth, (req, res) => {
|
||
const { q, service_type } = req.query;
|
||
|
||
if (!q || q.length < 2) {
|
||
return res.status(400).json({
|
||
error: 'Строка поиска должна содержать минимум 2 символа'
|
||
});
|
||
}
|
||
|
||
let query = `
|
||
SELECT iu.*,
|
||
u.name as user_name,
|
||
u.login as user_login,
|
||
u.email as user_email,
|
||
g.name as group_name
|
||
FROM idusers iu
|
||
LEFT JOIN users u ON iu.user_id = u.id
|
||
LEFT JOIN idgroups g ON iu.group_id = g.id
|
||
WHERE (iu.external_id LIKE ? OR iu.login LIKE ? OR u.name LIKE ? OR u.login LIKE ?)
|
||
`;
|
||
|
||
const params = [`%${q}%`, `%${q}%`, `%${q}%`, `%${q}%`];
|
||
|
||
if (service_type) {
|
||
query += ' AND iu.service_type = ?';
|
||
params.push(service_type);
|
||
}
|
||
|
||
query += ' ORDER BY iu.service_type, iu.external_id LIMIT 50';
|
||
|
||
db.all(query, params, (err, idusers) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка поиска идентификаторов:', err);
|
||
return res.status(500).json({ error: 'Ошибка поиска' });
|
||
}
|
||
|
||
// Парсим JSON metadata если есть
|
||
const result = (idusers || []).map(item => {
|
||
if (item.metadata) {
|
||
try {
|
||
item.metadata = JSON.parse(item.metadata);
|
||
} catch (e) {
|
||
item.metadata = {};
|
||
}
|
||
} else {
|
||
item.metadata = {};
|
||
}
|
||
return item;
|
||
});
|
||
|
||
res.json(result);
|
||
});
|
||
});
|
||
|
||
// GET /api2/idusers/stats - Статистика по идентификаторам (доступно всем аутентифицированным)
|
||
router.get('/api2/idusers/stats', requireAuth, (req, res) => {
|
||
// Получаем статистику по типам сервисов
|
||
const query = `
|
||
SELECT
|
||
service_type,
|
||
COUNT(*) as total_count,
|
||
COUNT(CASE WHEN is_active = 1 THEN 1 END) as active_count,
|
||
COUNT(DISTINCT user_id) as unique_users
|
||
FROM idusers
|
||
GROUP BY service_type
|
||
ORDER BY total_count DESC
|
||
`;
|
||
|
||
db.all(query, [], (err, stats) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения статистики:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения статистики' });
|
||
}
|
||
|
||
// Получаем общую статистику
|
||
db.get(`
|
||
SELECT
|
||
COUNT(*) as total_identifiers,
|
||
COUNT(DISTINCT user_id) as total_users,
|
||
COUNT(CASE WHEN is_active = 1 THEN 1 END) as total_active
|
||
FROM idusers
|
||
`, [], (err, totalStats) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения общей статистики:', err);
|
||
return res.status(500).json({ error: 'Ошибка получения статистики' });
|
||
}
|
||
|
||
res.json({
|
||
by_service_type: stats || [],
|
||
totals: totalStats || {},
|
||
timestamp: new Date().toISOString()
|
||
});
|
||
});
|
||
});
|
||
});
|
||
|
||
// 4. Инициализация при подключении модуля
|
||
const init = async () => {
|
||
try {
|
||
await createIdTables();
|
||
addDefaultGroups();
|
||
console.log('✅ API для внешних идентификаторов инициализирован');
|
||
} catch (error) {
|
||
console.error('❌ Ошибка инициализации API для внешних идентификаторов:', error.message);
|
||
}
|
||
};
|
||
|
||
// Запускаем инициализацию
|
||
init();
|
||
|
||
// Подключаем роутер к приложению
|
||
app.use(router);
|
||
|
||
// Экспортируем функции для использования в других модулях
|
||
return {
|
||
// Функция для получения внешнего идентификатора пользователя
|
||
getUserIdByExternalId: function(service_type, external_id, callback) {
|
||
db.get(
|
||
'SELECT user_id FROM idusers WHERE service_type = ? AND external_id = ? AND is_active = 1',
|
||
[service_type, external_id],
|
||
(err, result) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения идентификатора пользователя:', err);
|
||
return callback(err, null);
|
||
}
|
||
callback(null, result ? result.user_id : null);
|
||
}
|
||
);
|
||
},
|
||
|
||
// Функция для получения внешних идентификаторов пользователя
|
||
getUserExternalIds: function(user_id, service_type, callback) {
|
||
let query = 'SELECT * FROM idusers WHERE user_id = ? AND is_active = 1';
|
||
const params = [user_id];
|
||
|
||
if (service_type) {
|
||
query += ' AND service_type = ?';
|
||
params.push(service_type);
|
||
}
|
||
|
||
db.all(query, params, (err, results) => {
|
||
if (err) {
|
||
console.error('❌ Ошибка получения внешних идентификаторов:', err);
|
||
return callback(err, null);
|
||
}
|
||
|
||
// Парсим JSON metadata если есть
|
||
const formattedResults = (results || []).map(item => {
|
||
if (item.metadata) {
|
||
try {
|
||
item.metadata = JSON.parse(item.metadata);
|
||
} catch (e) {
|
||
item.metadata = {};
|
||
}
|
||
} else {
|
||
item.metadata = {};
|
||
}
|
||
return item;
|
||
});
|
||
|
||
callback(null, formattedResults);
|
||
});
|
||
},
|
||
|
||
// Функция для добавления или обновления идентификатора
|
||
upsertUserId: function(user_id, service_type, external_id, data, callback) {
|
||
const { login, ldap_group, group_id, metadata, is_active } = data || {};
|
||
|
||
db.get(
|
||
'SELECT id FROM idusers WHERE user_id = ? AND service_type = ? AND external_id = ?',
|
||
[user_id, service_type, external_id],
|
||
(err, existing) => {
|
||
if (err) {
|
||
return callback(err);
|
||
}
|
||
|
||
const metadataJson = metadata ? JSON.stringify(metadata) : null;
|
||
|
||
if (existing) {
|
||
// Обновляем существующий
|
||
db.run(
|
||
`UPDATE idusers SET
|
||
login = COALESCE(?, login),
|
||
ldap_group = COALESCE(?, ldap_group),
|
||
group_id = COALESCE(?, group_id),
|
||
metadata = COALESCE(?, metadata),
|
||
is_active = COALESCE(?, is_active),
|
||
updated_at = CURRENT_TIMESTAMP
|
||
WHERE id = ?`,
|
||
[
|
||
login || null,
|
||
ldap_group || null,
|
||
group_id || null,
|
||
metadataJson,
|
||
is_active !== undefined ? (is_active ? 1 : 0) : 1,
|
||
existing.id
|
||
],
|
||
function(err) {
|
||
callback(err, { updated: true, id: existing.id });
|
||
}
|
||
);
|
||
} else {
|
||
// Создаем новый
|
||
db.run(
|
||
`INSERT INTO idusers
|
||
(user_id, service_type, external_id, login, ldap_group, group_id, metadata, is_active)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||
[
|
||
user_id,
|
||
service_type,
|
||
external_id,
|
||
login || null,
|
||
ldap_group || null,
|
||
group_id || null,
|
||
metadataJson,
|
||
is_active !== undefined ? (is_active ? 1 : 0) : 1
|
||
],
|
||
function(err) {
|
||
callback(err, { created: true, id: this.lastID });
|
||
}
|
||
);
|
||
}
|
||
}
|
||
);
|
||
}
|
||
};
|
||
}; |