Compare commits

..

4 Commits

7 changed files with 101 additions and 66 deletions
+2
View File
@@ -203,6 +203,7 @@ jobs:
expose:
- "8000"
volumes:
- ./config.json:/app/config.json:ro
- app_uploads:/app/Web/uploads
- app_thumbnails:/app/Web/thumbnails
- app_previews:/app/Web/previews
@@ -225,6 +226,7 @@ jobs:
cp stop.sh release-bundle/stop.sh
cp restart.sh release-bundle/restart.sh
cp backup.sh release-bundle/backup.sh
cp config.json release-bundle/config.json
cp update.sh release-bundle/update.sh
cp init-admin.sh release-bundle/init-admin.sh
Binary file not shown.
+45
View File
@@ -92,6 +92,45 @@ SCHOOL_PERIODS = cfg.SCHOOL_PERIODS
# Apply the configuration for general use throughout the app
APP_VERSION = __version__
RELEASE_STATE_FILE = os.path.join(os.path.dirname(BASE_DIR), '.release-version')
def _get_asset_version():
"""Return a cache-busting asset version tied to deployment state."""
env_version = os.getenv('INVENTAR_ASSET_VERSION', '').strip()
if env_version:
return env_version
try:
if os.path.exists(RELEASE_STATE_FILE):
with open(RELEASE_STATE_FILE, 'r', encoding='utf-8') as f:
release_tag = f.read().strip()
if release_tag:
return release_tag
except Exception:
pass
return APP_VERSION
def _is_library_module_path(path):
"""Return True when the current request path belongs to the library module."""
if not path:
return False
library_prefixes = (
'/library',
'/library_',
'/student_cards',
)
return path.startswith(library_prefixes)
def _get_current_module(path):
"""Resolve the active UI module for navbar separation."""
if cfg.LIBRARY_MODULE_ENABLED and _is_library_module_path(path):
return 'library'
return 'inventory'
def _parse_money_value(value):
@@ -293,13 +332,19 @@ def _prepare_invoice_pdf_payload(invoice_data, borrow_doc=None, item_doc=None):
def inject_version():
"""Inject global template variables."""
is_admin = False
asset_version = _get_asset_version()
if 'username' in session:
try:
is_admin = us.check_admin(session['username'])
except Exception:
is_admin = False
current_module = _get_current_module(request.path)
return {
'APP_VERSION': APP_VERSION,
'ASSET_VERSION': asset_version,
'CURRENT_MODULE': current_module,
'school_periods': SCHOOL_PERIODS,
'library_module_enabled': cfg.LIBRARY_MODULE_ENABLED,
'student_cards_module_enabled': cfg.STUDENT_CARDS_MODULE_ENABLED,
+9 -66
View File
@@ -7,7 +7,7 @@
For commercial licensing inquiries: https://github.com/AIIrondev
-->
<!DOCTYPE html>
<html lang="en" data-module="inventory">
<html lang="en" data-module="{{ CURRENT_MODULE }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
@@ -20,8 +20,8 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css', v=APP_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/planned_appointments.css', v=APP_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css', v=ASSET_VERSION) }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/planned_appointments.css', v=ASSET_VERSION) }}">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<style>
@@ -369,7 +369,7 @@
<span class="module-label">Module:</span>
<div class="module-tabs">
<a href="{{ url_for('home') }}"
class="module-tab"
class="module-tab {% if CURRENT_MODULE == 'inventory' %}active{% endif %}"
id="inventoryModule"
data-module="inventory">
📦 Inventarsystem
@@ -377,7 +377,7 @@
{% if library_module_enabled %}
<div class="module-separator"></div>
<a href="{{ url_for('library_view') }}"
class="module-tab"
class="module-tab {% if CURRENT_MODULE == 'library' %}active{% endif %}"
id="libraryModule"
data-module="library">
📚 Bibliothek
@@ -386,48 +386,7 @@
</div>
</div>
{% endif %}
<script>
(function() {
// Detect current module based on URL and update data-module attribute
const currentPath = window.location.pathname;
const htmlTag = document.documentElement;
// Detect module and pages
const isLibraryModule = currentPath.includes('/library') ||
currentPath.includes('/library_admin') ||
currentPath.includes('/library_loans') ||
currentPath.includes('/student_cards');
const currentModule = isLibraryModule ? 'library' : 'inventory';
htmlTag.setAttribute('data-module', currentModule);
// Update module selector tabs
const invModule = document.getElementById('inventoryModule');
const libModule = document.getElementById('libraryModule');
if (currentModule === 'library') {
if (libModule) libModule.classList.add('active');
if (invModule) invModule.classList.remove('active');
} else {
if (invModule) invModule.classList.add('active');
if (libModule) libModule.classList.remove('active');
}
// Show/hide appropriate navbar based on current module
const invNavbar = document.getElementById('inventoryNavbar');
const libNavbar = document.getElementById('libraryNavbar');
if (currentModule === 'library') {
if (invNavbar) invNavbar.style.display = 'none';
if (libNavbar) libNavbar.style.display = '';
} else {
if (invNavbar) invNavbar.style.display = '';
if (libNavbar) libNavbar.style.display = 'none';
}
})();
</script>
{% if CURRENT_MODULE != 'library' %}
<nav class="navbar navbar-expand-lg navbar-dark" id="inventoryNavbar">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('home') }}" data-icon="📦">Inventarsystem</a>
@@ -490,9 +449,10 @@
</div>
</div>
</nav>
{% endif %}
{% if library_module_enabled %}
<nav class="navbar navbar-expand-lg navbar-dark" id="libraryNavbar" style="display: none;">
{% if library_module_enabled and CURRENT_MODULE == 'library' %}
<nav class="navbar navbar-expand-lg navbar-dark" id="libraryNavbar">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('library_view') }}" data-icon="📚">Bibliothek</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#libraryNavContent">
@@ -555,23 +515,6 @@
</div>
</nav>
{% endif %}
<script>
(function() {
// Show/hide appropriate navbar based on current module
const currentPath = window.location.pathname;
const invNavbar = document.getElementById('inventoryNavbar');
const libNavbar = document.getElementById('libraryNavbar');
if (currentPath.includes('/library')) {
if (invNavbar) invNavbar.style.display = 'none';
if (libNavbar) libNavbar.style.display = '';
} else {
if (invNavbar) invNavbar.style.display = '';
if (libNavbar) libNavbar.style.display = 'none';
}
})();
</script>
<div class="container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
+1
View File
@@ -42,6 +42,7 @@ services:
expose:
- "8000"
volumes:
- ./config.json:/app/config.json:ro
- ./Web:/app/Web
- app_uploads:/app/Web/uploads
- app_thumbnails:/app/Web/thumbnails
+39
View File
@@ -290,6 +290,44 @@ EOF
fi
}
ensure_runtime_config_json() {
local config_path backup_path
config_path="$SCRIPT_DIR/config.json"
if [ -d "$config_path" ]; then
backup_path="${config_path}.dir.$(date +%Y%m%d-%H%M%S).bak"
mv "$config_path" "$backup_path"
echo "Warning: moved unexpected directory $config_path to $backup_path"
fi
if [ ! -f "$config_path" ]; then
cat > "$config_path" <<'EOF'
{
"ver": "2.6.5",
"dbg": false,
"host": "0.0.0.0",
"port": 443,
"mongodb": {
"host": "mongodb",
"port": 27017,
"db": "Inventarsystem"
},
"modules": {
"library": {
"enabled": false
},
"student_cards": {
"enabled": false,
"default_borrow_days": 14,
"max_borrow_days": 365
}
}
}
EOF
echo "Created default runtime config at $config_path"
fi
}
ensure_app_image_loaded() {
if docker image inspect "$APP_IMAGE_VALUE" >/dev/null 2>&1; then
return 0
@@ -558,6 +596,7 @@ ensure_runtime_dependencies
setup_boot_autostart_service
ensure_tls_certificates
ensure_nginx_config_mount_source
ensure_runtime_config_json
setup_scheduled_jobs
configure_nuitka_mode
resolve_app_image
+5
View File
@@ -325,6 +325,11 @@ download_and_extract_bundle() {
cp -f "$tmp_dir/update.sh" "$PROJECT_DIR/update.sh"
fi
if [ ! -f "$PROJECT_DIR/config.json" ] && [ -f "$tmp_dir/config.json" ]; then
cp -f "$tmp_dir/config.json" "$PROJECT_DIR/config.json"
log_message "Installed default config.json from release bundle"
fi
chmod +x "$PROJECT_DIR/start.sh" "$PROJECT_DIR/stop.sh" "$PROJECT_DIR/restart.sh" "$PROJECT_DIR/update.sh" "$PROJECT_DIR/backup.sh"
}