From e3c4c738aa7814aa65f859d462646365e2faa627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Thu, 11 Jun 2026 16:29:24 +0400 Subject: [PATCH] =?UTF-8?q?feat:=20/export=3Fformat=3Djson=20=E2=80=94=20J?= =?UTF-8?q?SON=20export=20for=20admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/routes/entries.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/api/routes/entries.js b/src/api/routes/entries.js index d034462..dfa215c 100644 --- a/src/api/routes/entries.js +++ b/src/api/routes/entries.js @@ -85,9 +85,9 @@ function createEntriesRouter({ q }) { } }); - // GET /api/v1/entries/export — агрегированный список CIDR (text/plain) - // Доступен всем аутентифицированным пользователям. - // Admin: все компании или ?company=. User: только своя компания или ?client_id=. + // GET /api/v1/entries/export — агрегированный список CIDR + // ?format=json → JSON, иначе text/plain + // Только для админа. router.get('/export', async (req, res) => { try { let companyId = null; @@ -104,6 +104,16 @@ function createEntriesRouter({ q }) { } const cidrs = await q.getExportCIDRs(companyId); const aggregated = aggregateCIDRs(cidrs); + + const isJson = req.query.format === 'json'; + if (isJson) { + res.setHeader('Content-Type', 'application/json; charset=utf-8'); + const fname = (req.query.filename || 'white-list.json').replace(/[^\w\-_. ]/g, '_'); + const disp = req.query.view === '1' ? 'inline' : 'attachment'; + res.setHeader('Content-Disposition', `${disp}; filename="${fname}"`); + return res.json({ cidrs: aggregated, count: aggregated.length }); + } + res.setHeader('Content-Type', 'text/plain; charset=utf-8'); const fname = (req.query.filename || 'white-list.txt').replace(/[^\w\-_. ]/g, '_'); const disp = req.query.view === '1' ? 'inline' : 'attachment';