148 lines
7.0 KiB
JavaScript
148 lines
7.0 KiB
JavaScript
let db;
|
|
const LH = "ip NOT IN ('127.0.0.1', '::1', '::ffff:127.0.0.1')";
|
|
|
|
function init(database) {
|
|
db = database;
|
|
}
|
|
|
|
function getStats(req, res) {
|
|
db.get(`SELECT COUNT(DISTINCT session_id) as total FROM visitor_log WHERE ${LH}`, [], (err, totalRow) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
db.get(`SELECT COUNT(DISTINCT session_id) as today FROM visitor_log WHERE visit_date = date('now') AND ${LH}`, [], (err, todayRow) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
db.get(`SELECT COUNT(DISTINCT session_id) as week FROM visitor_log WHERE visit_date >= date('now', '-6 days') AND ${LH}`, [], (err, weekRow) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
db.get(`SELECT COUNT(DISTINCT session_id) as month FROM visitor_log WHERE visit_date >= date('now', 'start of month') AND ${LH}`, [], (err, monthRow) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
db.get(`SELECT COUNT(*) as page_views FROM visitor_log WHERE ${LH}`, [], (err, pvRow) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
db.get(`SELECT COUNT(DISTINCT ip) as unique_ips FROM visitor_log WHERE ${LH}`, [], (err, ipRow) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({
|
|
total: totalRow ? totalRow.total : 0,
|
|
today: todayRow ? todayRow.today : 0,
|
|
week: weekRow ? weekRow.week : 0,
|
|
month: monthRow ? monthRow.month : 0,
|
|
pageViews: pvRow ? pvRow.page_views : 0,
|
|
uniqueIps: ipRow ? ipRow.unique_ips : 0
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function getCountries(req, res) {
|
|
db.all(`SELECT COALESCE(NULLIF(country, ''), 'Другое') as country,
|
|
COALESCE(NULLIF(country_code, ''), '--') as country_code,
|
|
COUNT(DISTINCT session_id) as count
|
|
FROM visitor_log
|
|
WHERE ${LH}
|
|
GROUP BY COALESCE(NULLIF(country_code, ''), '--')
|
|
ORDER BY count DESC LIMIT 30`, [], (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json(rows || []);
|
|
});
|
|
}
|
|
|
|
function getLanguages(req, res) {
|
|
db.all(`SELECT accept_language, COUNT(DISTINCT session_id) as count
|
|
FROM visitor_log
|
|
WHERE accept_language IS NOT NULL AND accept_language != '' AND ${LH}
|
|
GROUP BY accept_language
|
|
ORDER BY count DESC`, [], (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
const parsed = (rows || []).map(r => {
|
|
const primary = (r.accept_language || '').split(',')[0].split(';')[0].trim();
|
|
const lang = primary.split('-')[0];
|
|
return { lang, raw: primary, count: r.count };
|
|
});
|
|
res.json(parsed);
|
|
});
|
|
}
|
|
|
|
function getDaily(req, res) {
|
|
db.all(`SELECT visit_date, COUNT(DISTINCT session_id) as count, COUNT(*) as page_views
|
|
FROM visitor_log
|
|
WHERE visit_date >= date('now', '-29 days') AND ${LH}
|
|
GROUP BY visit_date
|
|
ORDER BY visit_date ASC`, [], (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json(rows || []);
|
|
});
|
|
}
|
|
|
|
function getIPs(req, res) {
|
|
const limit = Math.min(parseInt(req.query.limit) || 50, 200);
|
|
const offset = parseInt(req.query.offset) || 0;
|
|
const { id, ip, country, lang, date_from, date_to, page } = req.query;
|
|
|
|
const whereClauses = [LH];
|
|
const params = [];
|
|
|
|
if (id) { whereClauses.push('id = ?'); params.push(parseInt(id)); }
|
|
if (ip) { whereClauses.push('ip LIKE ?'); params.push('%' + ip + '%'); }
|
|
if (country) { whereClauses.push('(country LIKE ? OR country_code LIKE ?)'); params.push('%' + country + '%'); params.push('%' + country + '%'); }
|
|
if (lang) { whereClauses.push('accept_language LIKE ?'); params.push('%' + lang + '%'); }
|
|
if (date_from) { whereClauses.push('visit_date >= ?'); params.push(date_from); }
|
|
if (date_to) { whereClauses.push('visit_date <= ?'); params.push(date_to); }
|
|
if (page) { whereClauses.push('page_path LIKE ?'); params.push('%' + page + '%'); }
|
|
|
|
const whereSQL = whereClauses.length > 0 ? 'WHERE ' + whereClauses.join(' AND ') : '';
|
|
|
|
db.get(`SELECT COUNT(*) as total FROM visitor_log ${whereSQL}`, params, (err, countRow) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
|
|
const allParams = [...params, limit, offset];
|
|
db.all(`SELECT id, ip, COALESCE(NULLIF(country, ''), 'Другое') as country,
|
|
country_code, session_id, visit_date, page_path,
|
|
COALESCE(NULLIF(accept_language, ''), '-') as accept_language,
|
|
created_at
|
|
FROM visitor_log
|
|
${whereSQL}
|
|
ORDER BY created_at DESC
|
|
LIMIT ? OFFSET ?`, allParams, (err, rows) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({
|
|
entries: rows || [],
|
|
total: countRow ? countRow.total : 0,
|
|
limit,
|
|
offset
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function getFilterOptions(req, res) {
|
|
db.all(`SELECT DISTINCT COALESCE(NULLIF(country, ''), 'Другое') as country
|
|
FROM visitor_log ORDER BY country`, [], (err, countries) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
db.all(`SELECT DISTINCT accept_language FROM visitor_log
|
|
WHERE accept_language IS NOT NULL AND accept_language != ''
|
|
ORDER BY accept_language`, [], (err, langs) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
db.all(`SELECT DISTINCT page_path FROM visitor_log ORDER BY page_path`, [], (err, pages) => {
|
|
if (err) return res.status(500).json({ error: err.message });
|
|
res.json({
|
|
countries: (countries || []).map(c => c.country),
|
|
languages: (langs || []).map(l => l.accept_language),
|
|
pages: (pages || []).map(p => p.page_path)
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function setupRoutes(app, authenticateToken) {
|
|
app.get('/api/admin/visitors/stats', authenticateToken, getStats);
|
|
app.get('/api/admin/visitors/countries', authenticateToken, getCountries);
|
|
app.get('/api/admin/visitors/languages', authenticateToken, getLanguages);
|
|
app.get('/api/admin/visitors/daily', authenticateToken, getDaily);
|
|
app.get('/api/admin/visitors/ips', authenticateToken, getIPs);
|
|
app.get('/api/admin/visitors/filters', authenticateToken, getFilterOptions);
|
|
}
|
|
|
|
module.exports = { init, setupRoutes };
|