Compare commits

...

3 Commits

7 changed files with 108 additions and 34 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
NUITKA_BUILD=0
INVENTAR_HTTP_PORT=10000
INVENTAR_HTTP_PORTS=10000
INVENTAR_APP_IMAGE=ghcr.io/aiirondev/legendary-octo-garbanzo:latest
INVENTAR_APP_IMAGE=ghcr.io/aiirondev/legendary-octo-garbanzo:v0.7.39
INVENTAR_APP_CPUS=1.0
INVENTAR_APP_MEM_LIMIT=384m
INVENTAR_APP_MEM_SWAP_LIMIT=768m
+1
View File
@@ -0,0 +1 @@
v0.7.42
+35 -8
View File
@@ -353,7 +353,7 @@ def _enforce_active_session_user():
@app.before_request
def _enforce_module_access():
endpoint = request.endpoint or ''
if endpoint == 'static' or endpoint.startswith('static') or request.path.startswith('/api/'):
if endpoint == 'static' or endpoint.startswith('static'):
return None
for name, matcher in cfg.MODULES._path_matchers.items():
@@ -363,7 +363,18 @@ def _enforce_module_access():
'inventory': "Inventar-Modul ist deaktiviert.",
'student_cards': "Schülerausweis-Modul ist deaktiviert."
}.get(name, f"{name.capitalize()}-Modul ist deaktiviert.")
return msg, 403
if request.path.startswith('/api/') or request.is_json:
return jsonify({'ok': False, 'message': msg}), 403
flash(msg, 'info')
if name != 'inventory' and cfg.MODULES.is_enabled('inventory'):
return redirect(url_for('home'))
elif name != 'library' and cfg.MODULES.is_enabled('library'):
return redirect(url_for('library_view'))
return redirect(url_for('my_borrowed_items'))
""" -----------------------------------------------------------After Request Handlers----------------------------------------------------------------------------- """
@@ -2619,7 +2630,8 @@ def home():
library_module_enabled=cfg.MODULES.is_enabled('library'),
student_cards_module_enabled=cfg.MODULES.is_enabled('student_cards'),
student_default_borrow_days=cfg.STUDENT_DEFAULT_BORROW_DAYS,
student_max_borrow_days=cfg.STUDENT_MAX_BORROW_DAYS
student_max_borrow_days=cfg.STUDENT_MAX_BORROW_DAYS,
open_item=request.args.get('open_item')
)
else:
permissions = _get_current_user_permissions() or us.build_default_permission_payload('standard_user')
@@ -2662,6 +2674,7 @@ def home_admin():
student_default_borrow_days=cfg.STUDENT_DEFAULT_BORROW_DAYS,
student_max_borrow_days=cfg.STUDENT_MAX_BORROW_DAYS,
school_info=_get_school_info_for_export(),
open_item=request.args.get('open_item')
)
@@ -4667,12 +4680,26 @@ def upload_item():
# Check if base code is unique for single-item uploads
if code_4 and item_count == 1 and not it.is_code_unique(code_4[0]):
error_msg = 'Der Code wird bereits verwendet. Bitte wählen Sie einen anderen Code.'
if is_mobile:
return jsonify({'success': False, 'message': error_msg}), 400
existing_item = it._get_items_collection().find_one({"code_4": code_4[0]})
if existing_item:
error_msg = 'Der Code wird bereits verwendet. Umleitung zum Eintrag.'
if is_mobile:
return jsonify({
'success': False,
'message': error_msg,
'existing_item_id': str(existing_item['_id']),
'redirect_to_item': True
}), 400
flash(error_msg, 'info')
return redirect(url_for(success_redirect_endpoint, open_item=str(existing_item['_id'])))
else:
flash(error_msg, 'error')
return redirect(url_for(success_redirect_endpoint))
error_msg = 'Der Code wird bereits verwendet. Bitte wählen Sie einen anderen Code.'
if is_mobile:
return jsonify({'success': False, 'message': error_msg}), 400
else:
flash(error_msg, 'error')
return redirect(url_for(success_redirect_endpoint))
# Validate optional per-item codes
if individual_codes:
+12
View File
@@ -4614,6 +4614,18 @@ function openItemQuick(id){
}
}
</style>
{% if open_item %}
<script>
document.addEventListener("DOMContentLoaded", function() {
if (typeof openEditModalFromServer === 'function') {
setTimeout(function() {
openEditModalFromServer('{{ open_item }}');
}, 500);
}
});
</script>
{% endif %}
{% endblock %}
<style>
/* Admin/Main Content Container align */
+12
View File
@@ -5716,4 +5716,16 @@ document.addEventListener('DOMContentLoaded', ()=>{
}
}
</style>
{% if open_item %}
<script>
document.addEventListener("DOMContentLoaded", function() {
if (typeof openEditModalFromServer === 'function') {
setTimeout(function() {
openEditModalFromServer('{{ open_item }}');
}, 500);
}
});
</script>
{% endif %}
{% endblock %}
Regular → Executable
View File
+47 -25
View File
@@ -1,41 +1,63 @@
version: "3.8"
services:
app:
build: .
container_name: inventory-app
image: ghcr.io/aiirondev/legendary-octo-garbanzo:v0.7.39
container_name: inventarsystem-app
restart: unless-stopped
environment:
- MONGO_URL=mongodb://mongodb:27017/inventar
- REDIS_URL=redis://redis:6379
- BASE_URL=https://inventar.maximiliangruendinger.de #alle öffentliche subdomains
ports:
- "10000:8000"
depends_on:
- mongodb
- redis
environment:
INVENTAR_MONGODB_HOST: mongodb
INVENTAR_MONGODB_PORT: "27017"
INVENTAR_MONGODB_DB: Inventarsystem
INVENTAR_BACKUP_FOLDER: /data/backups
INVENTAR_LOGS_FOLDER: /data/logs
expose:
- "8000"
volumes:
- ./config.json:/app/config.json:ro
- app_uploads:/app/Web/uploads
- app_thumbnails:/app/Web/thumbnails
- app_previews:/app/Web/previews
- app_qrcodes:/app/Web/QRCodes
- app_backups:/data/backups
- app_logs:/data/logs
mongodb:
image: mongo:latest
container_name: mongodb
image: mongo:7.0
container_name: inventarsystem-mongodb
restart: unless-stopped
volumes:
- mongo_data:/data/db
- mongodb_data:/data/db
healthcheck:
test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"]
interval: 10s
timeout: 5s
retries: 10
redis:
image: redis:alpine
container_name: redis
image: redis:7-alpine
container_name: inventarsystem-redis
restart: unless-stopped
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
# Der Tunnel-Name 'homeserver' muss zu deiner credentials.json passen
command: tunnel run homeserver
command: redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru
ports:
- "6379:6379"
volumes:
- ./config.yml:/etc/cloudflared/config.yml
- ./credentials.json:/etc/cloudflared/credentials.json
depends_on:
- app
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
mongo_data:
mongodb_data:
app_uploads:
app_thumbnails:
app_previews:
app_qrcodes:
app_backups:
app_logs:
redis_data: