proper cache busting

This commit is contained in:
2025-06-04 11:47:35 +02:00
parent 0f9f9d1b73
commit 88c3bc1b5b
20 changed files with 100 additions and 45 deletions

6
app.py
View File

@@ -15,6 +15,7 @@ from extensions import db, login_manager, csrf
from utils.email_templates import create_default_templates
from datetime import datetime
from sqlalchemy import text
from utils.asset_utils import get_asset_version
# Load environment variables
load_dotenv()
@@ -49,6 +50,11 @@ def create_app():
db.session.commit()
return dict(config=app.config, site_settings=site_settings)
@app.template_filter('asset_version')
def asset_version_filter(filename):
"""Template filter to get version hash for static assets"""
return get_asset_version(filename) or ''
# User loader for Flask-Login
@login_manager.user_loader
def load_user(user_id):

View File

@@ -6,10 +6,10 @@
<title>Login - DocuPulse</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/auth.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/auth.css') }}?v={{ 'css/auth.css'|asset_version }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css') }}?v={{ 'css/colors.css'|asset_version }}">
<link rel="stylesheet" href="{{ url_for('main.dynamic_colors') }}?v={{ site_settings.updated_at.timestamp() }}" onload="console.log('[CSS] Dynamic colors loaded with version:', '{{ site_settings.updated_at.timestamp() }}')">
<script src="{{ url_for('static', filename='js/color-logger.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/color-logger.js') }}?v={{ 'js/color-logger.js'|asset_version }}"></script>
</head>
<body>
<div class="container">

View File

@@ -6,10 +6,10 @@
<title>Register - DocuPulse</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/auth.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/auth.css') }}?v={{ 'css/auth.css'|asset_version }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css') }}?v={{ 'css/colors.css'|asset_version }}">
<link rel="stylesheet" href="{{ url_for('main.dynamic_colors') }}?v={{ site_settings.updated_at.timestamp() }}" onload="console.log('[CSS] Dynamic colors loaded with version:', '{{ site_settings.updated_at.timestamp() }}')">
<script src="{{ url_for('static', filename='js/color-logger.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/color-logger.js') }}?v={{ 'js/color-logger.js'|asset_version }}"></script>
</head>
<body>
<div class="container">

View File

@@ -9,12 +9,12 @@
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/file-grid.css', v=config.CSS_VERSION) }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/base.css', v=config.CSS_VERSION) }}" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css', v=config.CSS_VERSION) }}">
<link href="{{ url_for('static', filename='css/file-grid.css') }}?v={{ 'css/file-grid.css'|asset_version }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/base.css') }}?v={{ 'css/base.css'|asset_version }}" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/colors.css') }}?v={{ 'css/colors.css'|asset_version }}">
<link rel="stylesheet" href="{{ url_for('main.dynamic_colors') }}?v={{ site_settings.updated_at.timestamp() }}" onload="console.log('[CSS] Dynamic colors loaded with version:', '{{ site_settings.updated_at.timestamp() }}')">
{% block extra_css %}{% endblock %}
<script src="{{ url_for('static', filename='js/color-logger.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/color-logger.js') }}?v={{ 'js/color-logger.js'|asset_version }}"></script>
</head>
<body>
<!-- Navigation -->

View File

@@ -157,9 +157,9 @@
</div>
</div>
<script src="{{ url_for('static', filename='js/avatar-preview.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/avatar-preview.js') }}?v={{ 'js/avatar-preview.js'|asset_version }}"></script>
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/avatar-preview.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/avatar-preview.js') }}?v={{ 'js/avatar-preview.js'|asset_version }}"></script>
{% endblock %}

View File

@@ -43,7 +43,7 @@
</button>
</div>
</form>
<script src="{{ url_for('static', filename='js/contacts-filter.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/contacts-filter.js') }}?v={{ 'js/contacts-filter.js'|asset_version }}"></script>
</div>
<!-- Contacts List -->
@@ -206,5 +206,5 @@
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/contacts-filter.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/contacts-filter.js') }}?v={{ 'js/contacts-filter.js'|asset_version }}"></script>
{% endblock %}

View File

@@ -6,7 +6,7 @@
{% block extra_css %}
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/conversation.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/conversation.css') }}?v={{ 'css/conversation.css'|asset_version }}">
{% endblock %}
{% block content %}
@@ -200,8 +200,8 @@
window.currentUserId = "{{ current_user.id }}";
window.sendMessageUrl = "{{ url_for('conversations.send_message', conversation_id=conversation.id) }}";
</script>
<script src="{{ url_for('static', filename='js/chat-manager.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/conversation.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/member-management.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/chat-manager.js') }}?v={{ 'js/chat-manager.js'|asset_version }}"></script>
<script src="{{ url_for('static', filename='js/conversation.js') }}?v={{ 'js/conversation.js'|asset_version }}"></script>
<script src="{{ url_for('static', filename='js/member-management.js') }}?v={{ 'js/member-management.js'|asset_version }}"></script>
{% endblock %}
{% endblock content %}

View File

@@ -122,6 +122,6 @@
</div>
{% block extra_js %}
<script src="{{ url_for('static', filename='js/conversations-list.js') }}"></script>
<script src="{{ url_for('static', filename='js/conversations-list.js') }}?v={{ 'js/conversations-list.js'|asset_version }}"></script>
{% endblock %}
{% endblock %}

View File

@@ -6,7 +6,7 @@
{% block extra_css %}
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/member-management.css', v=config.CSS_VERSION) }}" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/member-management.css') }}?v={{ 'css/member-management.css'|asset_version }}" rel="stylesheet" />
<style>
.member-avatar {
width: 40px;
@@ -163,5 +163,5 @@
{% block extra_js %}
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="{{ url_for('static', filename='js/create-conversation.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/create-conversation.js') }}?v={{ 'js/create-conversation.js'|asset_version }}"></script>
{% endblock %}

View File

@@ -4,7 +4,7 @@
{% block title %}Dashboard - DocuPulse{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}?v={{ 'css/dashboard.css'|asset_version }}">
{% endblock %}
{% block content %}

View File

@@ -6,7 +6,7 @@
<title>DocuPulse - Legal Document Management</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/home.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/home.css') }}?v={{ 'css/home.css'|asset_version }}">
</head>
<body>
<!-- Navigation -->

View File

@@ -181,6 +181,6 @@
</div>
{% block extra_js %}
<script src="{{ url_for('static', filename='js/notifications.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/notifications.js') }}?v={{ 'js/notifications.js'|asset_version }}"></script>
{% endblock %}
{% endblock %}

View File

@@ -105,6 +105,6 @@
</div>
{% block extra_js %}
<script src="{{ url_for('static', filename='js/avatar-preview.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/avatar-preview.js') }}?v={{ 'js/avatar-preview.js'|asset_version }}"></script>
{% endblock %}
{% endblock %}

View File

@@ -4,7 +4,7 @@
{% block title %}{{ room.name }} - DocuPulse{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/room.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/room.css') }}?v={{ 'css/room.css'|asset_version }}">
{% endblock %}
{% block content %}
@@ -289,10 +289,10 @@
// Test if modules are working
console.log('Module system is working');
</script>
<script type="module" src="{{ url_for('static', filename='js/rooms/room.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/fileManager.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/viewManager.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/uploadManager.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/searchManager.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/modalManager.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/room.js') }}?v={{ 'js/rooms/room.js'|asset_version }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/fileManager.js') }}?v={{ 'js/rooms/fileManager.js'|asset_version }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/viewManager.js') }}?v={{ 'js/rooms/viewManager.js'|asset_version }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/uploadManager.js') }}?v={{ 'js/rooms/uploadManager.js'|asset_version }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/searchManager.js') }}?v={{ 'js/rooms/searchManager.js'|asset_version }}"></script>
<script type="module" src="{{ url_for('static', filename='js/rooms/modalManager.js') }}?v={{ 'js/rooms/modalManager.js'|asset_version }}"></script>
{% endblock %}

View File

@@ -6,7 +6,7 @@
{% block extra_css %}
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/room_members.css', v=config.CSS_VERSION) }}" rel="stylesheet" />
<link href="{{ url_for('static', filename='css/room_members.css') }}?v={{ 'css/room_members.css'|asset_version }}" rel="stylesheet" />
<style>
.form-check-input:checked {
background-color: var(--primary-color);
@@ -136,5 +136,5 @@
{% block extra_js %}
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="{{ url_for('static', filename='js/room-members.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/room-members.js') }}?v={{ 'js/room-members.js'|asset_version }}"></script>
{% endblock %}

View File

@@ -4,7 +4,7 @@
{% block title %}Rooms - DocuPulse{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/rooms.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/rooms.css') }}?v={{ 'css/rooms.css'|asset_version }}">
{% endblock %}
{% block content %}
@@ -133,6 +133,6 @@
</div>
{% block extra_js %}
<script src="{{ url_for('static', filename='js/rooms-list.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/rooms-list.js') }}?v={{ 'js/rooms-list.js'|asset_version }}"></script>
{% endblock %}
{% endblock %}

View File

@@ -13,7 +13,7 @@
{% block title %}Settings - DocuPulse{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}?v={{ 'css/settings.css'|asset_version }}">
{% endblock %}
{% block content %}
@@ -124,6 +124,6 @@
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/settings.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/events.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/settings.js') }}?v={{ 'js/settings.js'|asset_version }}"></script>
<script src="{{ url_for('static', filename='js/events.js') }}?v={{ 'js/events.js'|asset_version }}"></script>
{% endblock %}

View File

@@ -4,7 +4,7 @@
{% block title %}Starred - DocuPulse{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/starred.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/starred.css') }}?v={{ 'css/starred.css'|asset_version }}">
{% endblock %}
{% block content %}
@@ -42,6 +42,6 @@
{% endblock %}
{% block extra_js %}
<script type="module" src="{{ url_for('static', filename='js/file-grid.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/starred.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/file-grid.js') }}?v={{ 'js/file-grid.js'|asset_version }}"></script>
<script src="{{ url_for('static', filename='js/starred.js') }}?v={{ 'js/starred.js'|asset_version }}"></script>
{% endblock %}

View File

@@ -4,7 +4,7 @@
{% block title %}Trash - DocuPulse{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/trash.css', v=config.CSS_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/trash.css') }}?v={{ 'css/trash.css'|asset_version }}">
{% endblock %}
{% block content %}
@@ -48,6 +48,6 @@
{% endblock %}
{% block extra_js %}
<script type="module" src="{{ url_for('static', filename='js/file-grid.js', v=config.CSS_VERSION) }}"></script>
<script src="{{ url_for('static', filename='js/trash.js', v=config.CSS_VERSION) }}"></script>
<script type="module" src="{{ url_for('static', filename='js/file-grid.js') }}?v={{ 'js/file-grid.js'|asset_version }}"></script>
<script src="{{ url_for('static', filename='js/trash.js') }}?v={{ 'js/trash.js'|asset_version }}"></script>
{% endblock %}

49
utils/asset_utils.py Normal file
View File

@@ -0,0 +1,49 @@
import os
import hashlib
from functools import lru_cache
from flask import current_app
@lru_cache(maxsize=128)
def get_file_hash(filepath):
"""
Get the MD5 hash of a file's contents.
Uses LRU cache to avoid re-reading files that haven't changed.
Args:
filepath: The path to the file
Returns:
str: The MD5 hash of the file contents
"""
try:
with open(filepath, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
except (IOError, OSError):
return None
def get_asset_version(filename):
"""
Get the version hash for a static asset.
Args:
filename: The filename of the static asset
Returns:
str: The version hash or None if file not found
"""
if not filename:
return None
# Get the absolute path to the static file
static_dir = os.path.join(current_app.root_path, 'static')
filepath = os.path.join(static_dir, filename)
# Get the file hash
file_hash = get_file_hash(filepath)
# If file not found or error reading, return None
if not file_hash:
return None
# Return first 8 characters of hash as version
return file_hash[:8]