add analytics
This commit is contained in:
parent
8f5488faf3
commit
b17ed9b8c9
BIN
access_log.db
Normal file
BIN
access_log.db
Normal file
Binary file not shown.
74
app.py
74
app.py
@ -4,7 +4,8 @@ from PIL import Image
|
|||||||
import io
|
import io
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from datetime import datetime, date
|
import sqlite3
|
||||||
|
from datetime import datetime, date, timedelta
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
import diskcache
|
import diskcache
|
||||||
import json
|
import json
|
||||||
@ -193,6 +194,75 @@ def api_browse(subpath):
|
|||||||
'files': files
|
'files': files
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@app.route("/access-log")
|
||||||
|
@require_secret
|
||||||
|
def access_log():
|
||||||
|
# Get timeframe filter from query parameter; default to "today"
|
||||||
|
timeframe = request.args.get('timeframe', 'today')
|
||||||
|
now = datetime.now()
|
||||||
|
|
||||||
|
# Determine the start time based on the requested timeframe
|
||||||
|
if timeframe == 'today':
|
||||||
|
# Beginning of today
|
||||||
|
start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
elif timeframe == '7days':
|
||||||
|
start = now - timedelta(days=7)
|
||||||
|
elif timeframe == '30days':
|
||||||
|
start = now - timedelta(days=30)
|
||||||
|
elif timeframe == '365days':
|
||||||
|
start = now - timedelta(days=365)
|
||||||
|
else:
|
||||||
|
# Default to today if an unknown timeframe is passed
|
||||||
|
start = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
|
||||||
|
# Query the access log database for file access counts since the 'start' time
|
||||||
|
conn = sqlite3.connect('access_log.db')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute('''
|
||||||
|
SELECT full_path, COUNT(*) as access_count
|
||||||
|
FROM file_access_log
|
||||||
|
WHERE timestamp >= ?
|
||||||
|
GROUP BY full_path
|
||||||
|
ORDER BY access_count DESC
|
||||||
|
''', (start.isoformat(),))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return render_template("access_log.html", rows=rows, timeframe=timeframe)
|
||||||
|
|
||||||
|
def log_file_access(full_path):
|
||||||
|
"""
|
||||||
|
Log file access details to a SQLite database.
|
||||||
|
Records the timestamp, full file path, client IP, user agent, and referrer.
|
||||||
|
"""
|
||||||
|
# Connect to the database (this will create the file if it doesn't exist)
|
||||||
|
conn = sqlite3.connect('access_log.db')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
# Create the table if it doesn't exist
|
||||||
|
cursor.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS file_access_log (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
timestamp TEXT,
|
||||||
|
full_path TEXT,
|
||||||
|
ip_address TEXT,
|
||||||
|
user_agent TEXT,
|
||||||
|
referrer TEXT
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
# Gather information from the request
|
||||||
|
timestamp = datetime.now().isoformat()
|
||||||
|
ip_address = request.remote_addr
|
||||||
|
user_agent = request.headers.get('User-Agent')
|
||||||
|
referrer = request.headers.get('Referer')
|
||||||
|
|
||||||
|
# Insert the access record into the database
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT INTO file_access_log (timestamp, full_path, ip_address, user_agent, referrer)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
''', (timestamp, full_path, ip_address, user_agent, referrer))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
@app.route("/media/<path:filename>")
|
@app.route("/media/<path:filename>")
|
||||||
@require_secret
|
@require_secret
|
||||||
def serve_file(filename):
|
def serve_file(filename):
|
||||||
@ -203,6 +273,8 @@ def serve_file(filename):
|
|||||||
app.logger.error(f"File not found: {full_path}")
|
app.logger.error(f"File not found: {full_path}")
|
||||||
return "File not found", 404
|
return "File not found", 404
|
||||||
|
|
||||||
|
log_file_access(full_path)
|
||||||
|
|
||||||
mime, _ = mimetypes.guess_type(full_path)
|
mime, _ = mimetypes.guess_type(full_path)
|
||||||
mime = mime or 'application/octet-stream'
|
mime = mime or 'application/octet-stream'
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
flask-app:
|
flask-app:
|
||||||
image: python:3.11-slim
|
image: python:3.11-slim
|
||||||
|
|||||||
46
templates/access_log.html
Normal file
46
templates/access_log.html
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>File Access Log</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||||
|
table, th, td { border: 1px solid #ccc; border-collapse: collapse; padding: 8px; }
|
||||||
|
th { background-color: #f2f2f2; }
|
||||||
|
.btn { margin: 5px; padding: 8px 12px; text-decoration: none; background-color: #4CAF50; color: white; border-radius: 4px; }
|
||||||
|
.btn:hover { background-color: #45a049; }
|
||||||
|
.box { margin: 15px 0; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>File Access Log ({{ timeframe }})</h1>
|
||||||
|
<div class="box">
|
||||||
|
<a href="{{ url_for('access_log', timeframe='today') }}" class="btn">Today</a>
|
||||||
|
<a href="{{ url_for('access_log', timeframe='7days') }}" class="btn">Last 7 Days</a>
|
||||||
|
<a href="{{ url_for('access_log', timeframe='30days') }}" class="btn">Last 30 Days</a>
|
||||||
|
<a href="{{ url_for('access_log', timeframe='365days') }}" class="btn">Last 365 Days</a>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>File Path</th>
|
||||||
|
<th>Access Count</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for row in rows %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ row[0] }}</td>
|
||||||
|
<td>{{ row[1] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">No data available for the selected timeframe.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user