Changes to the Inventarsystem Workflow to Reflekt the new workflow and have an according set of buttons. So this removed all metioning of the duplication function.
Release Inventarsystem / release-docker (push) Successful in 2m15s

This commit is contained in:
2026-08-14 23:01:01 +02:00
parent d746b61a17
commit 7473334714
3 changed files with 14 additions and 394 deletions
+4 -202
View File
@@ -3927,7 +3927,6 @@ def upload_admin():
"""
Upload page route for inventory items.
Accessible to users with insert permission.
Supports duplication by passing duplicate_from parameter.
Returns:
flask.Response: Rendered template or redirect
@@ -3940,54 +3939,9 @@ def upload_admin():
flash('Ihnen ist es nicht gestattet auf dieser Internetanwendung, die eben besuchte Adrrese zu nutzen, versuchen sie es erneut nach dem sie sich mit einem berechtigten Nutzer angemeldet haben!', 'error')
return redirect(url_for('login'))
# Check if this is a duplication request
duplicate_from = request.args.get('duplicate_from')
duplicate_flag = request.args.get('duplicate') # Check for sessionStorage-based duplication
duplicate_data = None
# Handle the old method (duplicate_from parameter with item ID)
if duplicate_from:
try:
original_item = it.get_item(duplicate_from)
if original_item:
duplicate_data = {
'name': original_item.get('Name', ''),
'description': original_item.get('Beschreibung', ''),
'location': original_item.get('Ort', ''),
'room': original_item.get('Raum', ''),
'category': original_item.get('Kategorie', ''),
'year': original_item.get('Anschaffungsjahr', ''),
'cost': original_item.get('Anschaffungskosten', ''),
'filter1': original_item.get('Filter1', ''),
'filter2': original_item.get('Filter2', ''),
'filter3': original_item.get('Filter3', ''),
'images': original_item.get('Images', []),
'original_id': duplicate_from
}
# Copy all filter fields (Filter1_1 through Filter3_5)
for i in range(1, 4): # Filter1, Filter2, Filter3
for j in range(1, 6): # _1 through _5
filter_key = f'Filter{i}_{j}'
if filter_key in original_item:
duplicate_data[f'filter{i}_{j}'] = original_item[filter_key]
flash('Element wird dupliziert. Bitte überprüfen Sie die Daten und passen Sie sie bei Bedarf an.', 'info')
else:
flash('Ursprungs-Element für Duplizierung nicht gefunden.', 'error')
except Exception as e:
app.logger.warning(f"Error loading item for duplication: {e}")
flash('Fehler beim Laden der Duplizierungsdaten.', 'error')
# Handle the new method (sessionStorage-based duplication)
elif duplicate_flag == 'true':
# No server-side processing needed - JavaScript will handle sessionStorage data
# Just indicate that duplication mode is active
flash('Element wird dupliziert. Die Daten werden aus dem Session-Speicher geladen.', 'info')
return render_template(
'upload_admin.html',
username=session['username'],
duplicate_data=duplicate_data,
library_module_enabled=cfg.MODULES.is_enabled('library'),
student_cards_module_enabled=cfg.MODULES.is_enabled('student_cards'),
show_library_features=False,
@@ -4014,46 +3968,9 @@ def library_admin():
flash('Bibliotheks-Modul ist deaktiviert.', 'error')
return redirect(url_for('home_admin'))
duplicate_from = request.args.get('duplicate_from')
duplicate_flag = request.args.get('duplicate')
duplicate_data = None
if duplicate_from:
try:
original_item = it.get_item(duplicate_from)
if original_item:
duplicate_data = {
'name': original_item.get('Name', ''),
'description': original_item.get('Beschreibung', ''),
'location': original_item.get('Ort', ''),
'room': original_item.get('Raum', ''),
'category': original_item.get('Kategorie', ''),
'year': original_item.get('Anschaffungsjahr', ''),
'cost': original_item.get('Anschaffungskosten', ''),
'filter1': original_item.get('Filter1', ''),
'filter2': original_item.get('Filter2', ''),
'filter3': original_item.get('Filter3', ''),
'images': original_item.get('Images', []),
'original_id': duplicate_from
}
for i in range(1, 4):
for j in range(1, 6):
filter_key = f'Filter{i}_{j}'
if filter_key in original_item:
duplicate_data[f'filter{i}_{j}'] = original_item[filter_key]
flash('Buch wird dupliziert. Bitte überprüfen Sie die Daten und passen Sie sie bei Bedarf an.', 'info')
else:
flash('Ursprungs-Element für Duplizierung nicht gefunden.', 'error')
except Exception as e:
app.logger.warning(f"Error loading item for duplication: {e}")
flash('Fehler beim Laden der Duplizierungsdaten.', 'error')
elif duplicate_flag == 'true':
flash('Buch wird dupliziert. Die Daten werden aus dem Session-Speicher geladen.', 'info')
return render_template(
'upload_admin.html',
username=session['username'],
duplicate_data=duplicate_data,
library_module_enabled=cfg.MODULES.is_enabled('library'),
student_cards_module_enabled=cfg.MODULES.is_enabled('student_cards'),
show_library_features=True,
@@ -5388,18 +5305,18 @@ def upload_item():
individual_codes = []
if individual_codes_raw:
individual_codes = [c.strip() for c in str(individual_codes_raw).replace(',', '\n').splitlines() if c.strip()]
# Check if this is a duplication
is_duplicating = request.form.get('is_duplicating') == 'true'
# Get duplicate_images if duplicating
duplicate_images = request.form.getlist('duplicate_images') if is_duplicating else []
# Make sure duplicate_images is always a list, even if there's only one
if is_duplicating and duplicate_images and not isinstance(duplicate_images, list):
duplicate_images = [duplicate_images]
# Log details about each image
if is_duplicating and duplicate_images:
for i, img in enumerate(duplicate_images):
@@ -5819,121 +5736,6 @@ def upload_item():
flash(error_msg, 'error')
return redirect(url_for(success_redirect_endpoint))
@app.route('/duplicate_item', methods=['POST'])
def duplicate_item():
"""
Route for duplicating an existing item.
Returns JSON response with success status.
Enhanced for mobile browser compatibility.
Returns:
flask.Response: JSON response with success status and data
"""
try:
# Check authentication
if 'username' not in session:
return jsonify({'success': False, 'message': 'Nicht angemeldet'}), 401
# Check if user is admin
username = session['username']
current_permissions = us.get_effective_permissions(session['username'])
if not current_permissions['actions'].get('can_edit', False):
flash('Ihnen fehlen die nötigen Berechtigungen, um diese Aktion auszuführen.', 'error')
return redirect(url_for('home_admin'))
# Detect if request is from mobile device
is_mobile = 'Mobile' in request.headers.get('User-Agent', '')
is_ios = 'iPhone' in request.headers.get('User-Agent', '') or 'iPad' in request.headers.get('User-Agent', '')
# Log mobile duplication for debugging
if is_mobile:
app.logger.info(f"Mobile duplication from {request.headers.get('User-Agent', 'unknown')} by {encrypt_text(username)}")
# Get original item ID
original_item_id = request.form.get('original_item_id')
if not original_item_id:
return jsonify({'success': False, 'message': 'Ursprungs-Element-ID fehlt'}), 400
# Fetch original item data
original_item = it.get_item(original_item_id)
if not original_item:
return jsonify({'success': False, 'message': 'Ursprungs-Element nicht gefunden'}), 404
# Process filters as arrays (same as stored in database)
filter1_array = original_item.get('Filter', [])
filter2_array = original_item.get('Filter2', [])
filter3_array = original_item.get('Filter3', [])
# Ensure filters are arrays
if not isinstance(filter1_array, list):
filter1_array = [filter1_array] if filter1_array else []
if not isinstance(filter2_array, list):
filter2_array = [filter2_array] if filter2_array else []
if not isinstance(filter3_array, list):
filter3_array = [filter3_array] if filter3_array else []
# Verify image paths for mobile devices to avoid issues with non-existent images
images = original_item.get('Images', [])
verified_images = []
if is_mobile:
for img in images:
img_path = os.path.join(app.config['UPLOAD_FOLDER'], img)
if os.path.exists(img_path) and os.path.isfile(img_path):
verified_images.append(img)
else:
app.logger.warning(f"Image not found for duplication: {img}")
# If we lost images in verification, log it
if len(verified_images) < len(images):
app.logger.warning(f"Only {len(verified_images)} of {len(images)} images verified for mobile duplication")
else:
verified_images = images
# For iOS devices, add more diagnostics and reduce data size if needed
if is_ios:
# Check if images exist (we now use main images as thumbnails)
images_exist = []
for img in verified_images[:5]: # Only check first 5 to save time
img_path = os.path.join(app.config['UPLOAD_FOLDER'], img)
if os.path.exists(img_path):
images_exist.append(True)
else:
images_exist.append(False)
# Log detailed diagnostics
app.logger.info(f"iOS duplication details: {len(verified_images)} images, "
f"images available: {all(images_exist)}, "
f"filter sizes: {len(filter1_array)}, {len(filter2_array)}, {len(filter3_array)}")
return jsonify({
'success': True,
'message': 'Duplizierungsdaten erfolgreich vorbereitet',
'item_data': {
'name': original_item.get('Name', ''),
'description': original_item.get('Beschreibung', ''),
'location': original_item.get('Ort', ''),
'room': original_item.get('Raum', ''),
'category': original_item.get('Kategorie', ''),
'year': original_item.get('Anschaffungsjahr', ''),
'cost': original_item.get('Anschaffungskosten', ''),
'filter1': filter1_array,
'filter2': filter2_array,
'filter3': filter3_array,
'images': verified_images, # Using verified images instead of original
'isMobile': is_mobile,
'isIOS': is_ios
}
})
except Exception as e:
print(f"Error in duplicate_item: {e}")
return jsonify({'success': False, 'message': 'Serverfehler beim Duplizieren'}), 500
def _soft_delete_item_groups(db, root_item_ids, username):
"""Soft-delete one or more item groups and their borrow records."""
now = datetime.datetime.now()