Prima importazione
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const pool = require('../db');
|
||||
|
||||
// Helper for OTRS CE GenericInterface REST API calls
|
||||
async function otrsRequest(method, path, bodyData = {}) {
|
||||
const OTRS_API_USER = process.env.OTRS_API_USER;
|
||||
const OTRS_API_PASSWORD = process.env.OTRS_API_PASSWORD;
|
||||
const OTRS_API_URL = process.env.OTRS_API_URL;
|
||||
|
||||
if (!OTRS_API_URL || !OTRS_API_USER) {
|
||||
return null;
|
||||
}
|
||||
const url = `${OTRS_API_URL.replace(/\/$/, '')}${path.startsWith('/') ? path : '/' + path}`;
|
||||
const payload = {
|
||||
UserLogin: OTRS_API_USER,
|
||||
Password: OTRS_API_PASSWORD,
|
||||
...bodyData
|
||||
};
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`OTRS REST API error (${response.status}): ${errorText}`);
|
||||
}
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
|
||||
// GET /api/queues — Active queues
|
||||
router.get('/queues', async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT q.id, q.name, q.comments
|
||||
FROM queue q
|
||||
WHERE q.valid_id = 1
|
||||
ORDER BY q.name`
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error fetching queues:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/states — Ticket states with state type
|
||||
router.get('/states', async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT ts.id, ts.name, tst.name AS type_name
|
||||
FROM ticket_state ts
|
||||
JOIN ticket_state_type tst ON ts.type_id = tst.id
|
||||
WHERE ts.valid_id = 1
|
||||
ORDER BY ts.id`
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error fetching states:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/priorities — Ticket priorities
|
||||
router.get('/priorities', async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT id, name, color
|
||||
FROM ticket_priority
|
||||
WHERE valid_id = 1
|
||||
ORDER BY id`
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error fetching priorities:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/users — Active agents/operators
|
||||
router.get('/users', async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT id, login, first_name, last_name, title
|
||||
FROM users
|
||||
WHERE valid_id = 1
|
||||
ORDER BY last_name, first_name`
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error fetching users:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/types — Ticket types
|
||||
router.get('/types', async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT id, name
|
||||
FROM ticket_type
|
||||
WHERE valid_id = 1
|
||||
ORDER BY name`
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error fetching types:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/lock-types — Ticket lock types
|
||||
router.get('/lock-types', async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT id, name FROM ticket_lock_type WHERE valid_id = 1 ORDER BY id`
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error fetching lock types:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/customer-companies/search — Search customer companies
|
||||
router.get('/customer-companies/search', async (req, res) => {
|
||||
try {
|
||||
const { q } = req.query;
|
||||
if (!q) {
|
||||
return res.json([]);
|
||||
}
|
||||
const searchTerm = `%${q}%`;
|
||||
const result = await pool.query(
|
||||
`SELECT customer_id, name
|
||||
FROM customer_company
|
||||
WHERE valid_id = 1 AND (
|
||||
customer_id ILIKE $1 OR
|
||||
name ILIKE $1
|
||||
)
|
||||
ORDER BY name
|
||||
LIMIT 20`,
|
||||
[searchTerm]
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error searching customer companies:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/customer-users/search — Search customer users
|
||||
router.get('/customer-users/search', async (req, res) => {
|
||||
try {
|
||||
const { q, customer_company_id } = req.query;
|
||||
if (!q) {
|
||||
return res.json([]);
|
||||
}
|
||||
|
||||
// Try OTRS API first if configured
|
||||
const OTRS_API_URL = process.env.OTRS_API_URL;
|
||||
const OTRS_API_USER = process.env.OTRS_API_USER;
|
||||
if (OTRS_API_URL && OTRS_API_USER) {
|
||||
try {
|
||||
const searchParams = {
|
||||
Search: `*${q}*`,
|
||||
Valid: 1
|
||||
};
|
||||
if (customer_company_id) {
|
||||
searchParams.CustomerID = customer_company_id;
|
||||
}
|
||||
|
||||
const searchRes = await otrsRequest('POST', '/CustomerUserSearch', searchParams);
|
||||
let logins = [];
|
||||
if (searchRes) {
|
||||
if (Array.isArray(searchRes.CustomerUserID)) {
|
||||
logins = searchRes.CustomerUserID;
|
||||
} else if (searchRes.Data && Array.isArray(searchRes.Data.CustomerUserID)) {
|
||||
logins = searchRes.Data.CustomerUserID;
|
||||
} else if (Array.isArray(searchRes)) {
|
||||
logins = searchRes;
|
||||
}
|
||||
}
|
||||
|
||||
if (logins.length > 0) {
|
||||
// Limit to top 20 logins to avoid rate/performance issues
|
||||
const limitedLogins = logins.slice(0, 20);
|
||||
const detailPromises = limitedLogins.map(async (login) => {
|
||||
try {
|
||||
const detailRes = await otrsRequest('POST', '/CustomerUserGet', { UserLogin: login });
|
||||
const userObj = detailRes?.CustomerUser;
|
||||
if (userObj) {
|
||||
return {
|
||||
login: userObj.UserLogin || login,
|
||||
email: userObj.UserEmail || '',
|
||||
first_name: userObj.UserFirstname || '',
|
||||
last_name: userObj.UserLastname || '',
|
||||
customer_id: userObj.UserCustomerID || ''
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error fetching details for user ${login}:`, err.message);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const details = await Promise.all(detailPromises);
|
||||
const validUsers = details.filter(u => u !== null);
|
||||
if (validUsers.length > 0) {
|
||||
return res.json(validUsers);
|
||||
}
|
||||
}
|
||||
} catch (apiErr) {
|
||||
console.warn('OTRS CustomerUserSearch API request failed, falling back to local DB:', apiErr.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: local DB query
|
||||
const searchTerm = `%${q}%`;
|
||||
let queryText = `
|
||||
SELECT login, email, first_name, last_name, customer_id
|
||||
FROM customer_user
|
||||
WHERE valid_id = 1 AND (
|
||||
login ILIKE $1 OR
|
||||
email ILIKE $1 OR
|
||||
first_name ILIKE $1 OR
|
||||
last_name ILIKE $1
|
||||
)
|
||||
`;
|
||||
const queryParams = [searchTerm];
|
||||
|
||||
if (customer_company_id) {
|
||||
queryText += ` AND customer_id = $2`;
|
||||
queryParams.push(customer_company_id);
|
||||
}
|
||||
|
||||
queryText += ` ORDER BY last_name, first_name LIMIT 20`;
|
||||
|
||||
const result = await pool.query(queryText, queryParams);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error searching customer users:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/agents/search — Search active agents
|
||||
router.get('/agents/search', async (req, res) => {
|
||||
try {
|
||||
const { q } = req.query;
|
||||
const searchTerm = q ? `%${q}%` : '%';
|
||||
const result = await pool.query(
|
||||
`SELECT id, login, first_name, last_name
|
||||
FROM users
|
||||
WHERE valid_id = 1 AND (
|
||||
login ILIKE $1 OR
|
||||
first_name ILIKE $1 OR
|
||||
last_name ILIKE $1
|
||||
)
|
||||
ORDER BY last_name, first_name
|
||||
LIMIT 20`,
|
||||
[searchTerm]
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error searching agents:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/queues/search — Search active queues
|
||||
router.get('/queues/search', async (req, res) => {
|
||||
try {
|
||||
const { q } = req.query;
|
||||
const searchTerm = q ? `%${q}%` : '%';
|
||||
const result = await pool.query(
|
||||
`SELECT id, name
|
||||
FROM queue
|
||||
WHERE valid_id = 1 AND name ILIKE $1
|
||||
ORDER BY name
|
||||
LIMIT 20`,
|
||||
[searchTerm]
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error searching queues:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/states/search — Search active ticket states
|
||||
router.get('/states/search', async (req, res) => {
|
||||
try {
|
||||
const { q } = req.query;
|
||||
const searchTerm = q ? `%${q}%` : '%';
|
||||
const result = await pool.query(
|
||||
`SELECT id, name
|
||||
FROM ticket_state
|
||||
WHERE valid_id = 1 AND name ILIKE $1
|
||||
ORDER BY name
|
||||
LIMIT 20`,
|
||||
[searchTerm]
|
||||
);
|
||||
res.json(result.rows);
|
||||
} catch (err) {
|
||||
console.error('Error searching states:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user