add device_id

This commit is contained in:
lelo 2025-03-26 22:43:39 +00:00
parent 2b58bd74cc
commit 531e728b13
4 changed files with 50 additions and 44 deletions

View File

@ -32,17 +32,10 @@ def get_device_type(user_agent):
else: else:
return 'Other' return 'Other'
def shorten_referrer(url): def log_file_access(rel_path, ip_address, user_agent, device_id):
segments = [seg for seg in url.split('/') if seg]
segment = segments[-1]
# Decode all percent-encoded characters (like %20, %2F, etc.)
segment_decoded = unquote(segment)
return segment_decoded
def log_file_access(full_path, ip_address, user_agent, referrer):
""" """
Log file access details to a SQLite database. Log file access details to a SQLite database.
Records the timestamp, full file path, client IP, user agent, and referrer. Records the timestamp, full file path, client IP, user agent, and device_id.
""" """
global file_access_temp global file_access_temp
# Connect to the database (this will create the file if it doesn't exist) # Connect to the database (this will create the file if it doesn't exist)
@ -53,10 +46,10 @@ def log_file_access(full_path, ip_address, user_agent, referrer):
CREATE TABLE IF NOT EXISTS file_access_log ( CREATE TABLE IF NOT EXISTS file_access_log (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT, timestamp TEXT,
full_path TEXT, rel_path TEXT,
ip_address TEXT, ip_address TEXT,
user_agent TEXT, user_agent TEXT,
referrer TEXT device_id TEXT
) )
''') ''')
# Gather information from the request # Gather information from the request
@ -64,12 +57,12 @@ def log_file_access(full_path, ip_address, user_agent, referrer):
# Insert the access record into the database # Insert the access record into the database
cursor.execute(''' cursor.execute('''
INSERT INTO file_access_log (timestamp, full_path, ip_address, user_agent, referrer) INSERT INTO file_access_log (timestamp, rel_path, ip_address, user_agent, device_id)
VALUES (?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?)
''', (timestamp, full_path, ip_address, user_agent, referrer)) ''', (timestamp, rel_path, ip_address, user_agent, device_id))
conn.commit() conn.commit()
conn.close() conn.close()
file_access_temp.insert(0, [timestamp, full_path, ip_address, user_agent, referrer]) file_access_temp.insert(0, [timestamp, rel_path, ip_address, user_agent, device_id])
return return_file_access() return return_file_access()
def return_file_access(): def return_file_access():
@ -111,10 +104,10 @@ def dashboard():
# Raw file access counts for the table (top files) # Raw file access counts for the table (top files)
cursor.execute(''' cursor.execute('''
SELECT full_path, COUNT(*) as access_count SELECT rel_path, COUNT(*) as access_count
FROM file_access_log FROM file_access_log
WHERE timestamp >= ? WHERE timestamp >= ?
GROUP BY full_path GROUP BY rel_path
ORDER BY access_count DESC ORDER BY access_count DESC
LIMIT 20 LIMIT 20
''', (start.isoformat(),)) ''', (start.isoformat(),))
@ -132,14 +125,14 @@ def dashboard():
# Top files for bar chart # Top files for bar chart
cursor.execute(''' cursor.execute('''
SELECT full_path, COUNT(*) as access_count SELECT rel_path, COUNT(*) as access_count
FROM file_access_log FROM file_access_log
WHERE timestamp >= ? WHERE timestamp >= ?
GROUP BY full_path GROUP BY rel_path
ORDER BY access_count DESC ORDER BY access_count DESC
LIMIT 10 LIMIT 10
''', (start.isoformat(),)) ''', (start.isoformat(),))
top_files_data = [dict(full_path=row[0], access_count=row[1]) for row in cursor.fetchall()] top_files_data = [dict(rel_path=row[0], access_count=row[1]) for row in cursor.fetchall()]
# User agent distribution (aggregate by device type) # User agent distribution (aggregate by device type)
cursor.execute(''' cursor.execute('''
@ -157,20 +150,29 @@ def dashboard():
# Rename to user_agent_data for compatibility with the frontend # Rename to user_agent_data for compatibility with the frontend
user_agent_data = [dict(device=device, count=count) for device, count in device_counts.items()] user_agent_data = [dict(device=device, count=count) for device, count in device_counts.items()]
# Referrer distribution (shorten links) # Parent folder distribution
cursor.execute(''' cursor.execute('''
SELECT referrer, COUNT(*) as count SELECT rel_path, COUNT(*) as count
FROM file_access_log FROM file_access_log
WHERE timestamp >= ? WHERE timestamp >= ?
GROUP BY referrer GROUP BY rel_path
ORDER BY count DESC ORDER BY count DESC
LIMIT 10
''', (start.isoformat(),)) ''', (start.isoformat(),))
referrer_data = [] folder_data = {}
for row in cursor.fetchall(): for row in cursor.fetchall():
raw_ref = row[0] rel_path = row[0]
shortened = shorten_referrer(raw_ref) if raw_ref else "Direct/None" parent_folder = rel_path.rsplit('/', 1)[0] if '/' in rel_path else "Root"
referrer_data.append(dict(referrer=shortened, count=row[1])) folder_data[parent_folder] = folder_data.get(parent_folder, 0) + row[1]
# Convert the dictionary to a list of dictionaries
folder_data = [
dict(folder=folder, count=count)
for folder, count in folder_data.items()
]
# Sort by count in descending order and take the top 10
folder_data.sort(key=lambda x: x['count'], reverse=True)
folder_data = folder_data[:10]
# Aggregate IP addresses with counts # Aggregate IP addresses with counts
cursor.execute(''' cursor.execute('''
@ -208,13 +210,13 @@ def dashboard():
cursor.execute('SELECT COUNT(*) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),)) cursor.execute('SELECT COUNT(*) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),))
total_accesses = cursor.fetchone()[0] total_accesses = cursor.fetchone()[0]
# Use a separate query to count unique files (distinct full_path values) # Use a separate query to count unique files (distinct rel_path values)
cursor.execute('SELECT COUNT(DISTINCT full_path) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),)) cursor.execute('SELECT COUNT(DISTINCT rel_path) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),))
unique_files = cursor.fetchone()[0] unique_files = cursor.fetchone()[0]
# Use a separate query to count unique IP addresses # Use a separate query to count unique IP addresses
cursor.execute('SELECT COUNT(DISTINCT ip_address) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),)) cursor.execute('SELECT COUNT(DISTINCT device_id) FROM file_access_log WHERE timestamp >= ?', (start.isoformat(),))
unique_ips = cursor.fetchone()[0] unique_user = cursor.fetchone()[0]
conn.close() conn.close()
@ -224,8 +226,8 @@ def dashboard():
daily_access_data=daily_access_data, daily_access_data=daily_access_data,
top_files_data=top_files_data, top_files_data=top_files_data,
user_agent_data=user_agent_data, user_agent_data=user_agent_data,
referrer_data=referrer_data, folder_data=folder_data,
location_data=location_data, location_data=location_data,
total_accesses=total_accesses, total_accesses=total_accesses,
unique_files=unique_files, unique_files=unique_files,
unique_ips=unique_ips) unique_user=unique_user)

3
app.py
View File

@ -205,10 +205,9 @@ def serve_file(subpath):
if request.method == 'GET' and (not range_header or (range_header.startswith("bytes=0-") and range_header != "bytes=0-1")): if request.method == 'GET' and (not range_header or (range_header.startswith("bytes=0-") and range_header != "bytes=0-1")):
ip_address = request.remote_addr ip_address = request.remote_addr
user_agent = request.headers.get('User-Agent') user_agent = request.headers.get('User-Agent')
referrer = request.headers.get('Referer')
threading.Thread( threading.Thread(
target=a.log_file_access, target=a.log_file_access,
args=(full_path, ip_address, user_agent, referrer) args=(subpath, ip_address, user_agent, session['device_id'])
).start() ).start()
# Check cache first (using diskcache) # Check cache first (using diskcache)

View File

@ -2,6 +2,7 @@ from flask import Flask, render_template, request, redirect, url_for, session
from functools import wraps from functools import wraps
from datetime import datetime, date, timedelta from datetime import datetime, date, timedelta
import io import io
import os
import json import json
import qrcode import qrcode
import base64 import base64
@ -72,6 +73,10 @@ def require_secret(f):
# 6) If we have folders, proceed; otherwise show index # 6) If we have folders, proceed; otherwise show index
if session['folders']: if session['folders']:
# assume since visitor has a valid secret, they are ok with annonymous tracking
# this is required to track the devices connecting over the same ip address
if 'device_id' not in session:
session['device_id'] = os.urandom(32).hex()
return f(*args, **kwargs) return f(*args, **kwargs)
else: else:
return render_template('index.html') return render_template('index.html')

View File

@ -58,7 +58,7 @@
<div class="card text-white bg-warning"> <div class="card text-white bg-warning">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">eindeutige Nutzer</h5> <h5 class="card-title">eindeutige Nutzer</h5>
<p class="card-text">{{ unique_ips }}</p> <p class="card-text">{{ unique_user }}</p>
</div> </div>
</div> </div>
</div> </div>
@ -93,12 +93,12 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Referrer Distribution Chart --> <!-- Folder Distribution Chart -->
<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">Verteilung auf Ordner</h5> <h5 class="card-title">Verteilung auf Ordner</h5>
<canvas id="referrerChart"></canvas> <canvas id="folderChart"></canvas>
</div> </div>
</div> </div>
</div> </div>
@ -174,7 +174,7 @@
const topFilesData = {{ top_files_data|tojson }}; const topFilesData = {{ top_files_data|tojson }};
// Note: user_agent_data now contains 'device' and 'count' // Note: user_agent_data now contains 'device' and 'count'
const userAgentData = {{ user_agent_data|tojson }}; const userAgentData = {{ user_agent_data|tojson }};
const referrerData = {{ referrer_data|tojson }}; const folderData = {{ folder_data|tojson }};
// Access Trend Chart - Line Chart // Access Trend Chart - Line Chart
const ctxTrend = document.getElementById('accessTrendChart').getContext('2d'); const ctxTrend = document.getElementById('accessTrendChart').getContext('2d');
@ -235,14 +235,14 @@
options: { responsive: true } options: { responsive: true }
}); });
// Referrer Distribution - Pie Chart (with shortened referrers) // folder Distribution - Pie Chart (with shortened folders)
const ctxReferrer = document.getElementById('referrerChart').getContext('2d'); const ctxfolder = document.getElementById('folderChart').getContext('2d');
new Chart(ctxReferrer, { new Chart(ctxfolder, {
type: 'pie', type: 'pie',
data: { data: {
labels: referrerData.map(item => item.referrer), labels: folderData.map(item => item.folder),
datasets: [{ datasets: [{
data: referrerData.map(item => item.count) data: folderData.map(item => item.count)
}] }]
}, },
options: { responsive: true } options: { responsive: true }