add device_id
This commit is contained in:
parent
2b58bd74cc
commit
531e728b13
68
analytics.py
68
analytics.py
@ -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
3
app.py
@ -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)
|
||||||
|
|||||||
5
auth.py
5
auth.py
@ -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')
|
||||||
|
|||||||
@ -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 }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user