add distinct devices
This commit is contained in:
parent
4f88727321
commit
7daf2eea6e
47
analytics.py
47
analytics.py
@ -155,20 +155,49 @@ def dashboard():
|
|||||||
cursor = log_db.execute(query, params_for_filter)
|
cursor = log_db.execute(query, params_for_filter)
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
|
|
||||||
# 2. Daily access trend (line chart)
|
# 2. Distinct device trend
|
||||||
# We'll group by day using substr(timestamp, 1, 10) -> YYYY-MM-DD
|
# We'll group by hour if "today", by day if "7days"/"30days", by month if "365days"
|
||||||
|
if timeframe == 'today':
|
||||||
|
# Group by hour: substr(timestamp, 12, 2) -> HH
|
||||||
query = f'''
|
query = f'''
|
||||||
SELECT substr(timestamp, 1, 10) AS date, COUNT(*) AS count
|
SELECT substr(timestamp, 12, 2) AS bucket, COUNT(DISTINCT device_id) AS count
|
||||||
FROM file_access_log
|
FROM file_access_log
|
||||||
WHERE timestamp >= ? {filetype_filter_sql}
|
WHERE timestamp >= ? {filetype_filter_sql}
|
||||||
GROUP BY date
|
GROUP BY bucket
|
||||||
ORDER BY date
|
ORDER BY bucket
|
||||||
|
'''
|
||||||
|
elif timeframe in ('7days', '30days'):
|
||||||
|
# Group by day: substr(timestamp, 1, 10) -> YYYY-MM-DD
|
||||||
|
query = f'''
|
||||||
|
SELECT substr(timestamp, 1, 10) AS bucket, COUNT(DISTINCT device_id) AS count
|
||||||
|
FROM file_access_log
|
||||||
|
WHERE timestamp >= ? {filetype_filter_sql}
|
||||||
|
GROUP BY bucket
|
||||||
|
ORDER BY bucket
|
||||||
|
'''
|
||||||
|
elif timeframe == '365days':
|
||||||
|
# Group by month: substr(timestamp, 1, 7) -> YYYY-MM
|
||||||
|
query = f'''
|
||||||
|
SELECT substr(timestamp, 1, 7) AS bucket, COUNT(DISTINCT device_id) AS count
|
||||||
|
FROM file_access_log
|
||||||
|
WHERE timestamp >= ? {filetype_filter_sql}
|
||||||
|
GROUP BY bucket
|
||||||
|
ORDER BY bucket
|
||||||
|
'''
|
||||||
|
else:
|
||||||
|
# Default: group by day
|
||||||
|
query = f'''
|
||||||
|
SELECT substr(timestamp, 1, 10) AS bucket, COUNT(DISTINCT device_id) AS count
|
||||||
|
FROM file_access_log
|
||||||
|
WHERE timestamp >= ? {filetype_filter_sql}
|
||||||
|
GROUP BY bucket
|
||||||
|
ORDER BY bucket
|
||||||
'''
|
'''
|
||||||
with log_db:
|
with log_db:
|
||||||
cursor = log_db.execute(query, params_for_filter)
|
cursor = log_db.execute(query, params_for_filter)
|
||||||
daily_rows = cursor.fetchall()
|
distinct_device_data_rows = cursor.fetchall()
|
||||||
daily_access_data = [
|
distinct_device_data = [
|
||||||
dict(date=r[0], count=r[1]) for r in daily_rows
|
dict(bucket=r[0], count=r[1]) for r in distinct_device_data_rows
|
||||||
]
|
]
|
||||||
|
|
||||||
# 3. Timeframe-based aggregation
|
# 3. Timeframe-based aggregation
|
||||||
@ -322,7 +351,7 @@ def dashboard():
|
|||||||
"dashboard.html",
|
"dashboard.html",
|
||||||
timeframe=timeframe,
|
timeframe=timeframe,
|
||||||
rows=rows,
|
rows=rows,
|
||||||
daily_access_data=daily_access_data,
|
distinct_device_data=distinct_device_data,
|
||||||
user_agent_data=user_agent_data,
|
user_agent_data=user_agent_data,
|
||||||
folder_data=folder_data,
|
folder_data=folder_data,
|
||||||
location_data=location_data,
|
location_data=location_data,
|
||||||
|
|||||||
@ -70,8 +70,8 @@
|
|||||||
<div class="col-md-6 mb-4">
|
<div class="col-md-6 mb-4">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Downloads</h5>
|
<h5 class="card-title">eindeutige Nutzer nach Zeit</h5>
|
||||||
<canvas id="accessTrendChart"></canvas>
|
<canvas id="distinctDeviceChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Downloads nach Zeit</h5>
|
<h5 class="card-title">Downloads nach Zeit</h5>
|
||||||
<canvas id="timeframeChart"></canvas>
|
<canvas id="downloadTimeframeChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -170,7 +170,7 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Data passed from the backend as JSON
|
// Data passed from the backend as JSON
|
||||||
const dailyAccessData = {{ daily_access_data|tojson }};
|
const distinctDeviceData = {{ distinct_device_data|tojson }};
|
||||||
// Replace topFilesData usage with timeframeData for this chart
|
// Replace topFilesData usage with timeframeData for this chart
|
||||||
const timeframeData = {{ timeframe_data|tojson }};
|
const timeframeData = {{ timeframe_data|tojson }};
|
||||||
const userAgentData = {{ user_agent_data|tojson }};
|
const userAgentData = {{ user_agent_data|tojson }};
|
||||||
@ -206,31 +206,36 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Access Trend Chart - Line Chart
|
// Distinct Device Chart
|
||||||
const ctxTrend = document.getElementById('accessTrendChart').getContext('2d');
|
const ctxDistinctDevice = document.getElementById('distinctDeviceChart').getContext('2d');
|
||||||
new Chart(ctxTrend, {
|
new Chart(ctxDistinctDevice, {
|
||||||
type: 'line',
|
type: 'bar',
|
||||||
data: {
|
data: {
|
||||||
labels: dailyAccessData.map(item => item.date),
|
labels: shiftedLabels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Download Count',
|
label: 'Device Count',
|
||||||
data: dailyAccessData.map(item => item.count),
|
data: distinctDeviceData.map(item => item.count),
|
||||||
borderWidth: 2,
|
borderWidth: 2
|
||||||
fill: true
|
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
plugins: { legend: { position: 'top' } },
|
plugins: { legend: { display: false } },
|
||||||
scales: {
|
scales: {
|
||||||
x: { title: { display: true, text: 'Datum' } },
|
x: { title: { display: true, text: 'Time Range' } },
|
||||||
y: { title: { display: true, text: 'Download Count' } }
|
y: {
|
||||||
|
title: { display: true, text: 'Device Count' },
|
||||||
|
beginAtZero: true,
|
||||||
|
ticks: {
|
||||||
|
stepSize: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Timeframe Breakdown Chart - Bar Chart (for "today" timeframe)
|
// Timeframe Breakdown Chart - Bar Chart (for "today" timeframe)
|
||||||
const ctxTimeframe = document.getElementById('timeframeChart').getContext('2d');
|
const ctxTimeframe = document.getElementById('downloadTimeframeChart').getContext('2d');
|
||||||
new Chart(ctxTimeframe, {
|
new Chart(ctxTimeframe, {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: {
|
data: {
|
||||||
@ -238,15 +243,21 @@
|
|||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Download Count',
|
label: 'Download Count',
|
||||||
data: timeframeData.map(item => item.count),
|
data: timeframeData.map(item => item.count),
|
||||||
borderWidth: 1
|
borderWidth: 2
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
plugins: { legend: { display: false } },
|
plugins: { legend: { display: false } },
|
||||||
scales: {
|
scales: {
|
||||||
x: { title: { display: true, text: 'Local Time Range' } },
|
x: { title: { display: true, text: 'Time Range' } },
|
||||||
y: { title: { display: true, text: 'Download Count' } }
|
y: {
|
||||||
|
title: { display: true, text: 'Download Count' },
|
||||||
|
beginAtZero: true,
|
||||||
|
ticks: {
|
||||||
|
stepSize: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user