v0.5.10: /export — attachment default, ?view=1 inline, ?filename=custom
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ipwhitelist",
|
"name": "ipwhitelist",
|
||||||
"version": "0.5.9",
|
"version": "0.5.10",
|
||||||
"description": "IP WhiteList microservice for cloud provider",
|
"description": "IP WhiteList microservice for cloud provider",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ function createEntriesRouter({ q }) {
|
|||||||
const cidrs = await q.getExportCIDRs(companyId);
|
const cidrs = await q.getExportCIDRs(companyId);
|
||||||
const aggregated = aggregateCIDRs(cidrs);
|
const aggregated = aggregateCIDRs(cidrs);
|
||||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||||
res.setHeader('Content-Disposition', 'inline; filename="whitelist.txt"');
|
const fname = req.query.filename || 'white-list.txt';
|
||||||
|
const disp = req.query.view === '1' ? 'inline' : 'attachment';
|
||||||
|
res.setHeader('Content-Disposition', `${disp}; filename="${fname}"`);
|
||||||
res.send(aggregated.join('\n') + (aggregated.length ? '\n' : ''));
|
res.send(aggregated.join('\n') + (aggregated.length ? '\n' : ''));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).json({ error: e.message });
|
res.status(500).json({ error: e.message });
|
||||||
|
|||||||
+11
-4
@@ -39,8 +39,12 @@ function createRouter({ q, exportLimiter, aggregateCIDRs }) {
|
|||||||
|
|
||||||
if (!req.user.isAdmin) {
|
if (!req.user.isAdmin) {
|
||||||
// Обычный пользователь: только его компания.
|
// Обычный пользователь: только его компания.
|
||||||
// getOrCreateCompany — атомарная UPSERT, безопасна для параллельных вызовов.
|
// ?client_id= для мульти-компании
|
||||||
const company = await q.getOrCreateCompany(req.user.clientId, req.user.companyName);
|
const requestedId = (req.query.client_id || '').trim();
|
||||||
|
const effectiveClientId = (requestedId && req.user.allClientIds && req.user.allClientIds.includes(requestedId))
|
||||||
|
? requestedId
|
||||||
|
: req.user.clientId;
|
||||||
|
const company = await q.getOrCreateCompany(effectiveClientId, effectiveClientId);
|
||||||
companyId = company.id;
|
companyId = company.id;
|
||||||
} else if (req.query.company) {
|
} else if (req.query.company) {
|
||||||
// Администратор с необязательным фильтром по компании.
|
// Администратор с необязательным фильтром по компании.
|
||||||
@@ -56,9 +60,12 @@ function createRouter({ q, exportLimiter, aggregateCIDRs }) {
|
|||||||
const aggregated = aggregateCIDRs(cidrs);
|
const aggregated = aggregateCIDRs(cidrs);
|
||||||
|
|
||||||
// Content-Type: text/plain — чтобы браузер не пытался разбирать как HTML.
|
// Content-Type: text/plain — чтобы браузер не пытался разбирать как HTML.
|
||||||
// Content-Disposition: inline — открывается в браузере, а не скачивается.
|
// ?view=1 → inline (просмотр в браузере), иначе → attachment (скачивание)
|
||||||
|
// ?filename=X → своё имя файла, по умолчанию white-list.txt
|
||||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||||
res.setHeader('Content-Disposition', 'inline; filename="whitelist.txt"');
|
const fname = req.query.filename || 'white-list.txt';
|
||||||
|
const disp = req.query.view === '1' ? 'inline' : 'attachment';
|
||||||
|
res.setHeader('Content-Disposition', `${disp}; filename="${fname}"`);
|
||||||
|
|
||||||
// Один CIDR на строку. Если список пустой — возвращаем пустую строку (не ошибку).
|
// Один CIDR на строку. Если список пустой — возвращаем пустую строку (не ошибку).
|
||||||
res.send(aggregated.join('\n') + (aggregated.length ? '\n' : ''));
|
res.send(aggregated.join('\n') + (aggregated.length ? '\n' : ''));
|
||||||
|
|||||||
+11
-2
@@ -14,11 +14,20 @@ function createRouter() {
|
|||||||
|
|
||||||
router.get('/export', async (req, res) => {
|
router.get('/export', async (req, res) => {
|
||||||
const token = api.token(req);
|
const token = api.token(req);
|
||||||
const companyQuery = req.query.company ? '?company=' + parseInt(req.query.company, 10) : '';
|
// Прокидываем query-параметры в API
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (req.query.company) params.set('company', req.query.company);
|
||||||
|
if (req.query.client_id) params.set('client_id', req.query.client_id);
|
||||||
|
const qs = params.toString();
|
||||||
|
const companyQuery = qs ? '?' + qs : '';
|
||||||
try {
|
try {
|
||||||
const r = await api.get('/api/v1/entries/export' + companyQuery, token);
|
const r = await api.get('/api/v1/entries/export' + companyQuery, token);
|
||||||
res.set('Content-Type', 'text/plain; charset=utf-8');
|
res.set('Content-Type', 'text/plain; charset=utf-8');
|
||||||
res.set('Content-Disposition', 'inline; filename="whitelist.txt"');
|
// ?view=1 → inline (просмотр), иначе → attachment (скачивание)
|
||||||
|
// ?filename=X → своё имя, по умолчанию white-list.txt
|
||||||
|
const fname = req.query.filename || 'white-list.txt';
|
||||||
|
const disp = req.query.view === '1' ? 'inline' : 'attachment';
|
||||||
|
res.set('Content-Disposition', disp + '; filename="' + fname + '"');
|
||||||
res.send(r.data);
|
res.send(r.data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).send('Ошибка экспорта: ' + e.message);
|
res.status(500).send('Ошибка экспорта: ' + e.message);
|
||||||
|
|||||||
Reference in New Issue
Block a user