Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d6d6858002 |
+157
-655
@@ -2569,7 +2569,6 @@ def uploaded_file(filename):
|
||||
if denied:
|
||||
return denied
|
||||
|
||||
# 1. Try serving from MongoDB GridFS first
|
||||
try:
|
||||
fs = get_gridfs()
|
||||
grid_out = fs.find_one({'filename': filename})
|
||||
@@ -2582,15 +2581,6 @@ def uploaded_file(filename):
|
||||
except Exception as grid_err:
|
||||
app.logger.warning(f"GridFS lookup failed for {filename}: {grid_err}")
|
||||
|
||||
# 2. Fallback to production path for legacy local files
|
||||
prod_path = "/opt/Inventarsystem/Web/uploads"
|
||||
dev_path = app.config['UPLOAD_FOLDER']
|
||||
if os.path.exists(os.path.join(prod_path, filename)):
|
||||
return send_from_directory(prod_path, filename)
|
||||
# 3. Fallback to development path
|
||||
if os.path.exists(os.path.join(dev_path, filename)):
|
||||
return send_from_directory(dev_path, filename)
|
||||
|
||||
# 4. Use a placeholder image if file not found - first try SVG, then PNG
|
||||
svg_placeholder_path = os.path.join(app.static_folder, 'img', 'no-image.svg')
|
||||
png_placeholder_path = os.path.join(app.static_folder, 'img', 'no-image.png')
|
||||
@@ -5171,7 +5161,6 @@ def upload_item():
|
||||
Returns:
|
||||
flask.Response: Redirect to admin homepage
|
||||
"""
|
||||
# Check if the user is authenticated
|
||||
if 'username' not in session:
|
||||
return jsonify({'success': False, 'message': 'Nicht angemeldet'}), 401
|
||||
|
||||
@@ -5182,7 +5171,9 @@ def upload_item():
|
||||
permissions = _get_current_user_permissions() or us.build_default_permission_payload('standard_user')
|
||||
if not _action_access_allowed(permissions, 'can_insert'):
|
||||
return jsonify({'success': False, 'message': 'Einfüge-Rechte erforderlich'}), 403
|
||||
|
||||
|
||||
fs = get_gridfs()
|
||||
|
||||
can_access_admin_home = _page_access_allowed(permissions, 'home_admin') and _action_access_allowed(permissions, 'can_manage_settings')
|
||||
if can_access_admin_home:
|
||||
success_redirect_endpoint = 'home_admin'
|
||||
@@ -5269,14 +5260,9 @@ def upload_item():
|
||||
duplicate_images = mobile_data.get('duplicate_images', [])
|
||||
except json.JSONDecodeError as e:
|
||||
app.logger.error(f"Error parsing mobile data: {str(e)}")
|
||||
except Exception as e:
|
||||
error_msg = f"Fehler beim Verarbeiten der Formulardaten"
|
||||
app.logger.error(error_msg)
|
||||
if is_mobile:
|
||||
return jsonify({'success': False, 'message': error_msg}), 400
|
||||
else:
|
||||
flash('Fehler beim Verarbeiten der Formulardaten. Bitte versuchen Sie es erneut.', 'error')
|
||||
return redirect(url_for(success_redirect_endpoint))
|
||||
except:
|
||||
flash('Fehler beim Verarbeiten der Formulardaten. Bitte versuchen Sie es erneut.', 'error')
|
||||
return redirect(url_for(success_redirect_endpoint))
|
||||
|
||||
# Expand special "all values" selections for predefined filters.
|
||||
filter_upload = expand_filter_selection(filter_upload, 1)
|
||||
@@ -5328,10 +5314,6 @@ def upload_item():
|
||||
flash(error_msg, 'error')
|
||||
return redirect(url_for(success_redirect_endpoint))
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 1. PARSE AND UNIFY CODES
|
||||
# -------------------------------------------------------------------
|
||||
# Assuming `code_4` might come in as a single string or a list depending on your form setup
|
||||
primary_code_raw = request.form.get('code_4', '').strip()
|
||||
individual_codes_raw = request.form.get('individual_codes', '').strip()
|
||||
|
||||
@@ -5341,19 +5323,12 @@ def upload_item():
|
||||
all_item_codes.append(primary_code_raw)
|
||||
|
||||
if individual_codes_raw:
|
||||
# Split textarea by newlines, clean whitespace, and ignore empty lines
|
||||
extra_codes = [c.strip() for c in individual_codes_raw.replace('\r', '').split('\n') if c.strip()]
|
||||
|
||||
# Add to master list, ensuring no duplicates within the submitted list itself
|
||||
|
||||
for c in extra_codes:
|
||||
if c not in all_item_codes:
|
||||
all_item_codes.append(c)
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 2. OVERRIDE ITEM COUNT
|
||||
# -------------------------------------------------------------------
|
||||
# If the user scanned/generated codes, the amount of codes IS the item count.
|
||||
# Otherwise, fallback to a manual item_count field if it exists.
|
||||
if len(all_item_codes) > 0:
|
||||
item_count = len(all_item_codes)
|
||||
else:
|
||||
@@ -5362,9 +5337,6 @@ def upload_item():
|
||||
except ValueError:
|
||||
item_count = 1
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 3. IMAGE VALIDATION
|
||||
# -------------------------------------------------------------------
|
||||
if upload_mode != 'library' and not is_duplicating and not images and not duplicate_images and not book_cover_image:
|
||||
error_msg = 'Bitte laden Sie mindestens ein Bild hoch'
|
||||
if is_mobile:
|
||||
@@ -5373,14 +5345,9 @@ def upload_item():
|
||||
flash(error_msg, 'error')
|
||||
return redirect(url_for(success_redirect_endpoint))
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 4. UNIFIED DB UNIQUENESS VALIDATION
|
||||
# -------------------------------------------------------------------
|
||||
# Validate every code in our master list against the database
|
||||
for code in all_item_codes:
|
||||
if not it.is_code_unique(code):
|
||||
app.logger.info(f"DEBUG: Code '{code}' is not unique.")
|
||||
# Special case: If they only uploaded ONE item, redirect them to that existing item
|
||||
if item_count == 1:
|
||||
existing_item = it._get_items_collection().find_one({"code_4": code})
|
||||
if existing_item:
|
||||
@@ -5395,8 +5362,7 @@ def upload_item():
|
||||
|
||||
flash(error_msg, 'info')
|
||||
return redirect(url_for(success_redirect_endpoint, open_item=str(existing_item['_id'])))
|
||||
|
||||
# If multiple items are being uploaded, just throw a standard error
|
||||
|
||||
error_msg = f'Der Code "{code}" wird bereits von einem anderen Artikel verwendet. Bitte überprüfen Sie Ihre Eingaben.'
|
||||
if is_mobile:
|
||||
return jsonify({'success': False, 'message': error_msg}), 400
|
||||
@@ -5404,9 +5370,6 @@ def upload_item():
|
||||
flash(error_msg, 'error')
|
||||
return redirect(url_for(success_redirect_endpoint))
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# 5. BATCH CODE GENERATOR (Remains mostly unchanged)
|
||||
# -------------------------------------------------------------------
|
||||
def generate_unique_batch_code(base_code, position):
|
||||
"""Generate a unique code for every item in a batch if no specific code is provided."""
|
||||
if not base_code:
|
||||
@@ -5424,7 +5387,6 @@ def upload_item():
|
||||
suffix += 1
|
||||
return None
|
||||
|
||||
# Process any new uploaded images with robust error handling
|
||||
image_filenames = []
|
||||
processed_count = 0
|
||||
error_count = 0
|
||||
@@ -5433,650 +5395,190 @@ def upload_item():
|
||||
# Create a structured log entry for upload session
|
||||
upload_session_id = str(uuid.uuid4())[:8]
|
||||
app.logger.info(f"Starting image upload session {upload_session_id} - Files: {len(images)}, User: {encrypt_text(username)}")
|
||||
|
||||
# Ensure all required directories exist
|
||||
for directory in [app.config['UPLOAD_FOLDER']]:
|
||||
try:
|
||||
os.makedirs(directory, exist_ok=True)
|
||||
except Exception as e:
|
||||
app.logger.error(f"Failed to create directory {directory}: {str(e)}")
|
||||
|
||||
# Process each image independently
|
||||
|
||||
for index, image in enumerate(images):
|
||||
# In library mode, skip manual image uploads (use only book_cover_image from ISBN fetch)
|
||||
if upload_mode == 'library':
|
||||
app.logger.info(f"[Library Mode] Skipping manual image upload {index+1}/{len(images)}")
|
||||
app.logger.info(f"[Upload {upload_session_id}] Skipping manual upload (Library Mode)")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
image_log_prefix = f"[Upload {upload_session_id}][Image {index+1}/{len(images)}]"
|
||||
|
||||
if not image or not image.filename or image.filename == '':
|
||||
app.logger.warning(f"{image_log_prefix} Empty file or filename")
|
||||
|
||||
if not image or not image.filename:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Get file extension for special handling
|
||||
_, file_ext = os.path.splitext(image.filename.lower())
|
||||
is_png = file_ext.lower() == '.png'
|
||||
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Detected PNG file: {image.filename}")
|
||||
# Check file size
|
||||
image.seek(0, os.SEEK_END)
|
||||
file_size = image.tell() / (1024 * 1024) # Size in MB
|
||||
image.seek(0) # Reset file pointer
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} PNG file size: {file_size:.2f}MB")
|
||||
|
||||
# Check first few bytes for PNG signature and analyze header
|
||||
header_bytes = image.read(64) # Read more for thorough analysis
|
||||
image.seek(0) # Reset pointer
|
||||
png_signature = b'\x89PNG\r\n\x1a\n'
|
||||
is_valid_signature = header_bytes.startswith(png_signature)
|
||||
|
||||
# Create a hex dump of header for debugging
|
||||
hex_dump = ' '.join([f"{b:02x}" for b in header_bytes[:32]])
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} PNG header hex: {hex_dump}")
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} PNG signature valid: {is_valid_signature}, bytes: {header_bytes[:8]!r}")
|
||||
|
||||
# Analyze PNG chunks if signature is valid
|
||||
if is_valid_signature:
|
||||
try:
|
||||
# Look for IHDR chunk that should follow the signature
|
||||
if header_bytes[8:12] == b'IHDR':
|
||||
# Extract width and height from IHDR chunk (bytes 16-23)
|
||||
import struct
|
||||
width = struct.unpack('>I', header_bytes[16:20])[0]
|
||||
height = struct.unpack('>I', header_bytes[20:24])[0]
|
||||
bit_depth = header_bytes[24]
|
||||
color_type = header_bytes[25]
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} PNG dimensions from header: {width}x{height}, bit depth: {bit_depth}, color type: {color_type}")
|
||||
else:
|
||||
app.logger.warning(f"PNG DEBUG: {image_log_prefix} Expected IHDR chunk not found. Found: {header_bytes[8:12]!r}")
|
||||
except Exception as chunk_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error analyzing PNG chunks: {str(chunk_err)}")
|
||||
else:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Invalid PNG signature!")
|
||||
|
||||
|
||||
image_log_prefix = f"[Upload {upload_session_id}][Image {index + 1}/{len(images)}]"
|
||||
app.logger.info(f"{image_log_prefix} Processing: {image.filename}")
|
||||
|
||||
|
||||
try:
|
||||
# Comprehensive file validation with detailed logging
|
||||
# 1. Validation
|
||||
is_allowed, error_message = allowed_file(image.filename, image, max_size_mb=cfg.IMAGE_MAX_UPLOAD_MB)
|
||||
|
||||
if not is_allowed:
|
||||
app.logger.warning(f"{image_log_prefix} Validation failed: {error_message}")
|
||||
if is_png:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} PNG validation failed: {error_message}")
|
||||
skipped_count += 1
|
||||
if not is_mobile:
|
||||
flash(error_message, 'error')
|
||||
continue
|
||||
|
||||
# Get the file extension for content type determination
|
||||
|
||||
secure_name = secure_filename(image.filename)
|
||||
_, ext_part = os.path.splitext(secure_name)
|
||||
is_png = ext_part.lower() == '.png'
|
||||
|
||||
# Generate a completely unique filename using UUID
|
||||
unique_id = str(uuid.uuid4())
|
||||
timestamp = time.strftime("%Y%m%d%H%M%S")
|
||||
|
||||
# New filename format with UUID to ensure uniqueness
|
||||
saved_filename = f"{unique_id}_{timestamp}{ext_part}"
|
||||
app.logger.info(f"{image_log_prefix} Assigned unique filename: {saved_filename}")
|
||||
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Creating PNG with filename: {saved_filename}")
|
||||
|
||||
# For iOS devices, we need special handling for the file save
|
||||
if is_ios:
|
||||
app.logger.info(f"{image_log_prefix} Using iOS-specific file handling")
|
||||
# Save to a temporary file first to avoid iOS stream issues
|
||||
temp_path = os.path.join(app.config['UPLOAD_FOLDER'], f"temp_{saved_filename}")
|
||||
|
||||
try:
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Using iOS PNG save method")
|
||||
# Before saving, verify the file content again
|
||||
try:
|
||||
image.seek(0)
|
||||
pre_save_data = image.read(16)
|
||||
image.seek(0)
|
||||
pre_save_hex = ' '.join([f"{b:02x}" for b in pre_save_data])
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Pre-save data: {pre_save_hex}")
|
||||
except Exception as pre_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error checking pre-save data: {str(pre_err)}")
|
||||
|
||||
# For PNGs, try a direct binary save first
|
||||
if is_png:
|
||||
try:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Attempting binary save for iOS PNG")
|
||||
image.seek(0)
|
||||
png_data = image.read()
|
||||
with open(temp_path, 'wb') as f:
|
||||
f.write(png_data)
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Binary write complete, size: {len(png_data)} bytes")
|
||||
except Exception as bin_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Binary write failed: {str(bin_err)}")
|
||||
# Fall back to normal save
|
||||
image.seek(0)
|
||||
image.save(temp_path)
|
||||
else:
|
||||
image.save(temp_path)
|
||||
|
||||
# Validate the saved file
|
||||
if os.path.exists(temp_path) and os.path.getsize(temp_path) > 0:
|
||||
if is_png:
|
||||
file_size = os.path.getsize(temp_path)
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Temp PNG file saved successfully: {file_size/1024:.1f}KB")
|
||||
|
||||
# Verify it's a valid PNG
|
||||
try:
|
||||
with open(temp_path, 'rb') as f:
|
||||
png_header = f.read(16)
|
||||
png_signature = b'\x89PNG\r\n\x1a\n'
|
||||
is_valid = png_header.startswith(png_signature)
|
||||
|
||||
header_hex = ' '.join([f"{b:02x}" for b in png_header])
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Saved file header: {header_hex}")
|
||||
|
||||
if not is_valid:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Invalid PNG signature in saved file!")
|
||||
else:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Valid PNG signature confirmed in saved file")
|
||||
|
||||
# Try opening with PIL to confirm it's valid
|
||||
try:
|
||||
with Image.open(temp_path) as img:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Saved PNG validates with PIL: {img.format} {img.size}")
|
||||
except Exception as pil_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Saved PNG fails PIL validation: {str(pil_err)}")
|
||||
|
||||
except Exception as verify_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error verifying PNG: {str(verify_err)}")
|
||||
|
||||
# Rename to the final filename
|
||||
final_path = os.path.join(app.config['UPLOAD_FOLDER'], saved_filename)
|
||||
os.rename(temp_path, final_path)
|
||||
app.logger.info(f"{image_log_prefix} Successfully saved via iOS handler: {os.path.getsize(final_path)/1024:.1f}KB")
|
||||
else:
|
||||
if is_png:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Failed to save temp PNG file (zero size or missing)")
|
||||
raise Exception("Failed to save image file (zero size or missing)")
|
||||
except Exception as e:
|
||||
app.logger.error(f"{image_log_prefix} iOS save failed: {str(e)}")
|
||||
if is_png:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} iOS PNG save failed: {str(e)}")
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error type: {type(e).__name__}")
|
||||
# Log full traceback for PNG errors
|
||||
import io
|
||||
tb_output = io.StringIO()
|
||||
traceback.print_exc(file=tb_output)
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Full traceback:\n{tb_output.getvalue()}")
|
||||
|
||||
# Try regular save as fallback
|
||||
try:
|
||||
image.seek(0) # Reset file pointer
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Attempting fallback PNG save method")
|
||||
|
||||
image.save(os.path.join(app.config['UPLOAD_FOLDER'], saved_filename))
|
||||
app.logger.info(f"{image_log_prefix} Fallback save successful")
|
||||
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Fallback PNG save successful")
|
||||
except Exception as fallback_err:
|
||||
app.logger.error(f"{image_log_prefix} Fallback save also failed: {str(fallback_err)}")
|
||||
if is_png:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Fallback PNG save also failed: {str(fallback_err)}")
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error type: {type(fallback_err).__name__}")
|
||||
|
||||
error_count += 1
|
||||
continue
|
||||
else:
|
||||
# Regular file save for non-iOS devices
|
||||
try:
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Using standard PNG save method")
|
||||
|
||||
# Check file content before saving
|
||||
try:
|
||||
image.seek(0)
|
||||
pre_save_data = image.read(16)
|
||||
image.seek(0)
|
||||
pre_save_hex = ' '.join([f"{b:02x}" for b in pre_save_data])
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Pre-save data: {pre_save_hex}")
|
||||
|
||||
# Check if it's really a PNG
|
||||
png_signature = b'\x89PNG\r\n\x1a\n'
|
||||
if not pre_save_data.startswith(png_signature):
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} File does not have valid PNG signature before save!")
|
||||
except Exception as pre_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error checking pre-save data: {str(pre_err)}")
|
||||
|
||||
# Try an alternative saving method for PNGs with detailed error tracking
|
||||
try:
|
||||
# Read the image data directly
|
||||
image.seek(0)
|
||||
image_data = image.read()
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Read {len(image_data)} bytes of PNG data")
|
||||
|
||||
# Write it manually to file
|
||||
save_path = os.path.join(app.config['UPLOAD_FOLDER'], saved_filename)
|
||||
with open(save_path, 'wb') as f:
|
||||
f.write(image_data)
|
||||
|
||||
file_size = os.path.getsize(save_path)
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Direct binary PNG write successful: {file_size/1024:.1f}KB")
|
||||
|
||||
# Verify the saved file
|
||||
try:
|
||||
with open(save_path, 'rb') as f:
|
||||
saved_header = f.read(16)
|
||||
header_hex = ' '.join([f"{b:02x}" for b in saved_header])
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Saved PNG header: {header_hex}")
|
||||
|
||||
is_valid = saved_header.startswith(png_signature)
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Saved PNG has valid signature: {is_valid}")
|
||||
|
||||
if is_valid:
|
||||
# Additional validation with PIL
|
||||
try:
|
||||
with Image.open(save_path) as img:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Saved PNG validates with PIL: {img.format} {img.size}")
|
||||
except Exception as pil_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Saved PNG fails PIL validation: {str(pil_err)}")
|
||||
except Exception as verify_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error verifying saved PNG: {str(verify_err)}")
|
||||
|
||||
except Exception as png_write_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Direct PNG write failed: {str(png_write_err)}")
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error type: {type(png_write_err).__name__}")
|
||||
|
||||
# Log traceback for PNG errors
|
||||
import io
|
||||
tb_output = io.StringIO()
|
||||
traceback.print_exc(file=tb_output)
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Binary write traceback:\n{tb_output.getvalue()}")
|
||||
|
||||
# Fall back to standard method
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Attempting standard PIL save method")
|
||||
image.seek(0)
|
||||
image.save(os.path.join(app.config['UPLOAD_FOLDER'], saved_filename))
|
||||
else:
|
||||
# Standard save for non-PNG files
|
||||
image.save(os.path.join(app.config['UPLOAD_FOLDER'], saved_filename))
|
||||
|
||||
app.logger.info(f"{image_log_prefix} Standard save successful")
|
||||
except Exception as save_err:
|
||||
app.logger.error(f"{image_log_prefix} Failed to save file: {str(save_err)}")
|
||||
if is_png:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Standard PNG save failed: {str(save_err)}")
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error type: {type(save_err).__name__}")
|
||||
|
||||
# Log traceback for PNG errors
|
||||
import io
|
||||
tb_output = io.StringIO()
|
||||
traceback.print_exc(file=tb_output)
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Standard save traceback:\n{tb_output.getvalue()}")
|
||||
|
||||
# Try one last method - save as a different format
|
||||
try:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Attempting last resort conversion to WebP")
|
||||
image.seek(0)
|
||||
|
||||
# Try to convert PNG to WebP as a last resort
|
||||
with Image.open(image) as img:
|
||||
# Ensure RGBA for transparency
|
||||
if img.mode != 'RGBA':
|
||||
img = img.convert('RGBA')
|
||||
webp_path = os.path.splitext(os.path.join(app.config['UPLOAD_FOLDER'], saved_filename))[0] + '.webp'
|
||||
img.save(webp_path, 'WEBP')
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Successfully saved as WebP instead: {webp_path}")
|
||||
# Update the saved_filename to reflect the new extension
|
||||
saved_filename = os.path.basename(webp_path)
|
||||
except Exception as webp_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Final WebP conversion failed: {str(webp_err)}")
|
||||
|
||||
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
# Verify the file was saved correctly
|
||||
saved_path = os.path.join(app.config['UPLOAD_FOLDER'], saved_filename)
|
||||
if not os.path.exists(saved_path) or os.path.getsize(saved_path) == 0:
|
||||
app.logger.error(f"{image_log_prefix} Saved file is missing or empty: {saved_path}")
|
||||
if is_png:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Saved PNG is missing or empty: {saved_path}")
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
# Special verification for PNG files
|
||||
if is_png:
|
||||
try:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Verifying saved PNG: {saved_path}")
|
||||
saved_size = os.path.getsize(saved_path) / 1024.0 # in KB
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Saved PNG size: {saved_size:.1f}KB")
|
||||
|
||||
# Check file integrity by trying to open it
|
||||
try:
|
||||
with Image.open(saved_path) as img:
|
||||
png_width, png_height = img.size
|
||||
png_mode = img.mode
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Saved PNG valid: {png_width}x{png_height}, mode: {png_mode}")
|
||||
except Exception as png_verify_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} PNG verification failed: {str(png_verify_err)}")
|
||||
|
||||
# Try to fix by copying from the original
|
||||
try:
|
||||
image.seek(0)
|
||||
with open(saved_path, 'wb') as f:
|
||||
f.write(image.read())
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Attempted to fix PNG by direct copy")
|
||||
except Exception as png_fix_err:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} PNG fix attempt failed: {str(png_fix_err)}")
|
||||
except Exception as e:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} PNG verification error: {str(e)}")
|
||||
|
||||
# Generate optimized versions (thumbnails and previews)
|
||||
optimization_success = False
|
||||
try:
|
||||
# Log original file size before optimization
|
||||
original_path = os.path.join(app.config['UPLOAD_FOLDER'], saved_filename)
|
||||
original_size = os.path.getsize(original_path)
|
||||
|
||||
# Get original image dimensions
|
||||
original_dimensions = "unknown"
|
||||
try:
|
||||
with Image.open(original_path) as img:
|
||||
original_dimensions = f"{img.width}x{img.height}"
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Original PNG dimensions: {original_dimensions}, mode: {img.mode}")
|
||||
except Exception as dim_err:
|
||||
app.logger.warning(f"{image_log_prefix} Could not get image dimensions: {str(dim_err)}")
|
||||
if is_png:
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Could not get PNG dimensions: {str(dim_err)}")
|
||||
app.logger.error(f"PNG DEBUG: {image_log_prefix} Error type: {type(dim_err).__name__}")
|
||||
|
||||
|
||||
app.logger.info(f"{image_log_prefix} Starting optimization for {saved_filename} ({original_size/1024:.1f}KB, {original_dimensions})")
|
||||
|
||||
# PNG-specific optimization options
|
||||
if is_png:
|
||||
app.logger.info(f"PNG DEBUG: {image_log_prefix} Starting PNG optimization")
|
||||
# For PNGs, we might need different parameters
|
||||
optimization_result = generate_optimized_versions(
|
||||
saved_filename,
|
||||
max_original_width=500,
|
||||
target_size_kb=100, # Higher target for PNGs to maintain transparency
|
||||
debug_prefix=f"PNG DEBUG: {image_log_prefix}"
|
||||
)
|
||||
else:
|
||||
# Standard optimization for non-PNG images
|
||||
optimization_result = generate_optimized_versions(saved_filename, max_original_width=500, target_size_kb=80)
|
||||
|
||||
# Log file size after optimization
|
||||
if optimization_result['success'] and optimization_result['original']:
|
||||
optimized_name = optimization_result['original']
|
||||
optimized_path = os.path.join(app.config['UPLOAD_FOLDER'], optimized_name)
|
||||
|
||||
if os.path.exists(optimized_path):
|
||||
optimized_size = os.path.getsize(optimized_path)
|
||||
reduction = (1 - (optimized_size / original_size)) * 100 if original_size > 0 else 0
|
||||
|
||||
# Get optimized dimensions
|
||||
optimized_dimensions = "unknown"
|
||||
try:
|
||||
with Image.open(optimized_path) as img:
|
||||
optimized_dimensions = f"{img.width}x{img.height}"
|
||||
except Exception as dim_err:
|
||||
app.logger.warning(f"{image_log_prefix} Could not get optimized dimensions: {str(dim_err)}")
|
||||
|
||||
app.logger.info(
|
||||
f"{image_log_prefix} Optimization results:\n"
|
||||
f" File: {saved_filename} → {optimized_name}\n"
|
||||
f" Size: {original_size/1024:.1f}KB → {optimized_size/1024:.1f}KB ({reduction:.1f}% reduction)\n"
|
||||
f" Dimensions: {original_dimensions} → {optimized_dimensions}"
|
||||
)
|
||||
|
||||
# Use the optimized filename
|
||||
saved_filename = optimized_name
|
||||
else:
|
||||
app.logger.warning(f"{image_log_prefix} Optimized file reported success but not found: {optimized_path}")
|
||||
else:
|
||||
app.logger.warning(f"{image_log_prefix} Optimization failed or returned no file")
|
||||
except Exception as e:
|
||||
app.logger.error(f"{image_log_prefix} Optimization failed: {str(e)}")
|
||||
|
||||
# No fallback thumbnail generation needed as we only use the main image
|
||||
|
||||
# Always add the filename to our list even if optimization failed
|
||||
# We'll use the original in that case
|
||||
image_filenames.append(saved_filename)
|
||||
|
||||
# 2. Read directly into memory (Bypasses OS-level file quirks and iOS temp-file bugs)
|
||||
image_bytes = image.read()
|
||||
|
||||
# 3. Process, standardize, and optimize using Pillow in-memory
|
||||
optimized_io = io.BytesIO()
|
||||
with Image.open(io.BytesIO(image_bytes)) as img:
|
||||
# Ensure safe color mode
|
||||
if img.mode not in ('RGB', 'RGBA'):
|
||||
img = img.convert('RGBA')
|
||||
|
||||
# Standardize dimensions (e.g., max width 500px)
|
||||
max_width = 500
|
||||
if img.width > max_width:
|
||||
ratio = max_width / img.width
|
||||
new_size = (max_width, int(img.height * ratio))
|
||||
img = img.resize(new_size, Image.Resampling.LANCZOS)
|
||||
|
||||
# Export as WebP to a memory buffer
|
||||
# (WebP naturally handles transparency, drastically reduces size, and bypasses PNG signature corruption)
|
||||
img.save(optimized_io, format='WEBP', quality=85, optimize=True)
|
||||
|
||||
optimized_io.seek(0)
|
||||
|
||||
new_filename = f"{uuid.uuid4().hex}_{int(time.time())}.webp"
|
||||
|
||||
file_id = fs.put(
|
||||
optimized_io,
|
||||
filename=new_filename,
|
||||
content_type='image/webp',
|
||||
metadata={
|
||||
'original_filename': secure_name,
|
||||
'upload_session': upload_session_id
|
||||
}
|
||||
)
|
||||
|
||||
image_filenames.append(file_id)
|
||||
processed_count += 1
|
||||
app.logger.info(f"{image_log_prefix} Successfully processed")
|
||||
|
||||
|
||||
final_size_kb = len(optimized_io.getvalue()) / 1024
|
||||
app.logger.info(
|
||||
f"{image_log_prefix} Saved to GridFS as {new_filename} | ID: {file_id} | Size: {final_size_kb:.1f}KB")
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"{image_log_prefix} Unexpected error: {str(e)}")
|
||||
app.logger.error(f"{image_log_prefix} Processing failed: {str(e)}")
|
||||
error_count += 1
|
||||
# Continue with the next image
|
||||
|
||||
# Log summary of upload session
|
||||
|
||||
app.logger.info(f"Upload session {upload_session_id} completed: {processed_count} processed, {error_count} errors, {skipped_count} skipped")
|
||||
|
||||
# Handle duplicate images if duplicating
|
||||
# 1. Duplikate verarbeiten (Direkt via MongoDB / GridFS)
|
||||
if duplicate_images:
|
||||
app.logger.info(f"Processing {len(duplicate_images)} duplicate images: {duplicate_images}")
|
||||
|
||||
# For mobile browsers, we need to verify the duplicate images exist first
|
||||
verified_duplicates = []
|
||||
for dup_img in duplicate_images:
|
||||
# Try looking in different paths
|
||||
# Add all possible paths where images might be stored
|
||||
dev_upload_path = app.config['UPLOAD_FOLDER']
|
||||
prod_upload_path = '/var/Inventarsystem/Web/uploads'
|
||||
|
||||
# Also look for image variations with suffixes that might be in the path
|
||||
name_part, ext_part = os.path.splitext(dup_img)
|
||||
possible_filenames = [
|
||||
dup_img,
|
||||
f"{name_part}.webp", # Check WebP first
|
||||
f"{name_part}.jpg", # In case it was converted to JPG
|
||||
f"{name_part}.png", # In case it was saved as PNG
|
||||
]
|
||||
|
||||
possible_paths = []
|
||||
for filename in possible_filenames:
|
||||
possible_paths.extend([
|
||||
os.path.join(dev_upload_path, filename), # Development upload path
|
||||
os.path.join(prod_upload_path, filename), # Production upload path
|
||||
])
|
||||
|
||||
app.logger.info(f"Looking for duplicate image {dup_img} in paths: {possible_paths}")
|
||||
|
||||
# Try to find the original image
|
||||
found = False
|
||||
for path in possible_paths:
|
||||
if os.path.exists(path) and os.path.isfile(path):
|
||||
verified_duplicates.append((dup_img, path))
|
||||
app.logger.info(f"Found duplicate image at: {path}")
|
||||
found = True
|
||||
break
|
||||
|
||||
if not found:
|
||||
app.logger.warning(f"Duplicate image not found: {dup_img}")
|
||||
# Try to find any image with a similar filename (removing size or resolution parts)
|
||||
# This handles cases where the filename may have variations like "_800" suffix
|
||||
base_name = os.path.splitext(dup_img)[0]
|
||||
base_name = re.sub(r'_\d+$', '', base_name) # Remove trailing _NUMBER
|
||||
|
||||
if len(base_name) > 5: # Only if we have a meaningful base name
|
||||
app.logger.info(f"Trying to find similar images with base name: {base_name}")
|
||||
|
||||
# Search in development directory
|
||||
dev_files = os.listdir(app.config['UPLOAD_FOLDER']) if os.path.exists(app.config['UPLOAD_FOLDER']) else []
|
||||
# Search in production directory
|
||||
prod_path = "/var/Inventarsystem/Web/uploads"
|
||||
prod_files = os.listdir(prod_path) if os.path.exists(prod_path) else []
|
||||
|
||||
# Combine all files
|
||||
all_files = dev_files + prod_files
|
||||
|
||||
# Find similar files
|
||||
for f in all_files:
|
||||
if base_name in f:
|
||||
img_path = os.path.join(app.config['UPLOAD_FOLDER'], f)
|
||||
if not os.path.exists(img_path):
|
||||
img_path = os.path.join(prod_path, f)
|
||||
|
||||
if os.path.exists(img_path) and os.path.isfile(img_path):
|
||||
app.logger.info(f"Found similar image: {f} at {img_path}")
|
||||
verified_duplicates.append((f, img_path))
|
||||
found = True
|
||||
break
|
||||
|
||||
# If we still can't find anything, just use a placeholder
|
||||
if not found:
|
||||
app.logger.warning(f"Could not find any similar image for: {dup_img}, will use placeholder")
|
||||
|
||||
# Create copies of verified images with new unique filenames
|
||||
app.logger.info(f"Processing {len(duplicate_images)} duplicate images from GridFS: {duplicate_images}")
|
||||
duplicate_image_copies = []
|
||||
|
||||
# Create a placeholder name for each image that wasn't found
|
||||
placeholder_used = False
|
||||
original_count = len(duplicate_images)
|
||||
|
||||
# Process each original image - either use found file or placeholder
|
||||
|
||||
for i, dup_img in enumerate(duplicate_images):
|
||||
# Look for corresponding verified image
|
||||
found_image = None
|
||||
for verified_img, src_path in verified_duplicates:
|
||||
if verified_img == dup_img:
|
||||
found_image = (verified_img, src_path)
|
||||
break
|
||||
|
||||
try:
|
||||
# Generate a new unique filename (same for real or placeholder)
|
||||
unique_id = str(uuid.uuid4())
|
||||
timestamp = time.strftime("%Y%m%d%H%M%S")
|
||||
_, ext_part = os.path.splitext(dup_img) if dup_img else '.jpg'
|
||||
new_filename = f"{unique_id}_{timestamp}{ext_part}"
|
||||
|
||||
# If we found the image, copy it
|
||||
if found_image:
|
||||
dup_img, src_path = found_image
|
||||
app.logger.info(f"Copying image {i+1}/{original_count} from {src_path} to {new_filename}")
|
||||
|
||||
# Copy the image file to the new name
|
||||
dst_path = os.path.join(app.config['UPLOAD_FOLDER'], new_filename)
|
||||
|
||||
# Make sure the target directory exists
|
||||
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
|
||||
|
||||
# Copy the file
|
||||
shutil.copy2(src_path, dst_path)
|
||||
|
||||
# Verify the file was copied successfully
|
||||
if os.path.exists(dst_path):
|
||||
app.logger.info(f"Successfully copied image to {dst_path}")
|
||||
else:
|
||||
app.logger.error(f"Failed to copy image to {dst_path}")
|
||||
# If copy fails, use placeholder
|
||||
raise Exception("Copy failed - will use placeholder")
|
||||
|
||||
# Generate optimized versions (thumbnails and previews) for the new copy
|
||||
try:
|
||||
result = generate_optimized_versions(new_filename, max_original_width=500, target_size_kb=80)
|
||||
app.logger.info(f"Generated optimized versions: {result}")
|
||||
if result['success'] and result['original']:
|
||||
new_filename = result['original']
|
||||
except Exception as e:
|
||||
app.logger.error(f"Error generating optimized versions for {new_filename}: {e}")
|
||||
# If optimization fails, at least keep the original file
|
||||
result = {'original': new_filename}
|
||||
|
||||
|
||||
# If we didn't find the image, use a placeholder
|
||||
# Suche das Originalbild direkt in der GridFS-Datenbank
|
||||
existing_file = fs.find_one({"filename": dup_img})
|
||||
|
||||
# Fallback: Falls der exakte Name nicht gefunden wird, suche über Regex nach dem Basisnamen
|
||||
if not existing_file:
|
||||
base_name = re.sub(r'_\d+(?=\.[^.]+$)', '', dup_img) # Entfernt Suffixe wie _800
|
||||
base_name_no_ext = os.path.splitext(base_name)[0]
|
||||
|
||||
if len(base_name_no_ext) > 5:
|
||||
app.logger.info(f"Trying regex search for base name: {base_name_no_ext}")
|
||||
existing_file = fs.find_one({"filename": {"$regex": f"^{re.escape(base_name_no_ext)}"}})
|
||||
|
||||
new_filename = f"{uuid.uuid4().hex}_{int(time.time())}.webp"
|
||||
|
||||
if existing_file:
|
||||
app.logger.info(f"Found image in GridFS for {dup_img}. Duplicating...")
|
||||
# Bilddaten in den Speicher laden und direkt als neue Datei in GridFS ablegen
|
||||
image_data = existing_file.read()
|
||||
|
||||
fs.put(
|
||||
image_data,
|
||||
filename=new_filename,
|
||||
content_type=existing_file.content_type,
|
||||
metadata={'original_duplicate_of': dup_img}
|
||||
)
|
||||
duplicate_image_copies.append(new_filename)
|
||||
processed_count += 1
|
||||
else:
|
||||
app.logger.warning(f"Using placeholder for image {i+1}/{original_count} (original: {dup_img})")
|
||||
|
||||
# Copy placeholder to uploads directory with the new filename
|
||||
placeholder_path = os.path.join(app.static_folder, 'img', 'no-image.svg')
|
||||
if not os.path.exists(placeholder_path):
|
||||
placeholder_path = os.path.join(app.static_folder, 'img', 'no-image.png')
|
||||
|
||||
app.logger.warning(f"Could not find {dup_img} in GridFS. Using placeholder.")
|
||||
placeholder_path = os.path.join(app.static_folder, 'img', 'no-image.png')
|
||||
|
||||
if os.path.exists(placeholder_path):
|
||||
dst_path = os.path.join(app.config['UPLOAD_FOLDER'], new_filename)
|
||||
shutil.copy2(placeholder_path, dst_path)
|
||||
app.logger.info(f"Copied placeholder image to {dst_path}")
|
||||
with open(placeholder_path, 'rb') as pf:
|
||||
placeholder_data = pf.read()
|
||||
|
||||
fs.put(
|
||||
placeholder_data,
|
||||
filename=new_filename,
|
||||
content_type='image/png',
|
||||
metadata={'is_placeholder': True}
|
||||
)
|
||||
duplicate_image_copies.append(new_filename)
|
||||
placeholder_used = True
|
||||
|
||||
# Skip the optimization step for placeholder images
|
||||
# Just add directly to the list of image filenames
|
||||
continue
|
||||
else:
|
||||
app.logger.error(f"Placeholder image not found at {placeholder_path}")
|
||||
# Create a simple placeholder file
|
||||
with open(os.path.join(app.config['UPLOAD_FOLDER'], new_filename), 'w') as f:
|
||||
f.write("Placeholder")
|
||||
placeholder_used = True
|
||||
# Skip the optimization step
|
||||
continue
|
||||
|
||||
# Add the new filename to our list (either copied or placeholder)
|
||||
duplicate_image_copies.append(new_filename)
|
||||
processed_count += 1
|
||||
|
||||
app.logger.info(f"Processed image {i+1}/{original_count}: {new_filename}")
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Error processing image {i+1}/{original_count} ({dup_img}): {str(e)}")
|
||||
|
||||
app.logger.error(f"Error duplicating image {dup_img}: {str(e)}")
|
||||
error_count += 1
|
||||
|
||||
# Log placeholder usage
|
||||
|
||||
if placeholder_used:
|
||||
app.logger.warning(f"Used placeholders for some missing images during duplication")
|
||||
|
||||
# Log if no images were processed
|
||||
if not duplicate_image_copies:
|
||||
app.logger.warning(f"No duplicate images were processed")
|
||||
if duplicate_images:
|
||||
app.logger.warning(f"Original had {len(duplicate_images)} images, but none were copied")
|
||||
|
||||
# Add the new image copies to our list of filenames
|
||||
app.logger.warning("Used placeholders for some missing images during duplication")
|
||||
|
||||
image_filenames.extend(duplicate_image_copies)
|
||||
|
||||
# Handle book cover image if provided
|
||||
# 2. Buchcover verarbeiten
|
||||
if book_cover_image:
|
||||
# Verify the book cover image exists
|
||||
full_path = os.path.join(app.config['UPLOAD_FOLDER'], book_cover_image)
|
||||
if os.path.exists(full_path) and os.path.isfile(full_path):
|
||||
# Create a unique filename for the book cover
|
||||
unique_id = str(uuid.uuid4())
|
||||
timestamp = time.strftime("%Y%m%d%H%M%S")
|
||||
_, ext_part = os.path.splitext(book_cover_image)
|
||||
|
||||
new_filename = f"{unique_id}_{timestamp}_book_cover{ext_part}"
|
||||
new_path = os.path.join(app.config['UPLOAD_FOLDER'], new_filename)
|
||||
|
||||
# Copy the file to the new unique name
|
||||
shutil.copy2(full_path, new_path)
|
||||
|
||||
# Use the new filename instead
|
||||
image_filenames.append(new_filename)
|
||||
app.logger.info(f"Copied book cover from {book_cover_image} to {new_filename}")
|
||||
else:
|
||||
app.logger.warning(f"Book cover image not found: {book_cover_image}")
|
||||
|
||||
# If location is not in the predefined list, add it
|
||||
new_filename = f"{uuid.uuid4().hex}_{int(time.time())}_book_cover.webp"
|
||||
|
||||
# Prüfen, ob das Cover noch als lokale temporäre Datei existiert (z.B. von einer API geladen)
|
||||
local_path = os.path.join(app.config.get('UPLOAD_FOLDER', ''), book_cover_image)
|
||||
|
||||
try:
|
||||
if os.path.exists(local_path):
|
||||
# Lokales Bild einlesen, zu WebP optimieren und in GridFS schieben
|
||||
with Image.open(local_path) as img:
|
||||
if img.mode not in ('RGB', 'RGBA'):
|
||||
img = img.convert('RGBA')
|
||||
|
||||
optimized_io = io.BytesIO()
|
||||
img.save(optimized_io, format='WEBP', quality=85, optimize=True)
|
||||
optimized_io.seek(0)
|
||||
|
||||
fs.put(
|
||||
optimized_io,
|
||||
filename=new_filename,
|
||||
content_type='image/webp',
|
||||
metadata={'is_book_cover': True}
|
||||
)
|
||||
image_filenames.append(new_filename)
|
||||
app.logger.info(f"Processed local book cover and saved to GridFS: {new_filename}")
|
||||
else:
|
||||
# Falls es bereits in GridFS liegt, einfach duplizieren
|
||||
existing_cover = fs.find_one({"filename": book_cover_image})
|
||||
if existing_cover:
|
||||
fs.put(
|
||||
existing_cover.read(),
|
||||
filename=new_filename,
|
||||
content_type=existing_cover.content_type,
|
||||
metadata={'is_book_cover': True}
|
||||
)
|
||||
image_filenames.append(new_filename)
|
||||
app.logger.info(f"Duplicated existing GridFS book cover: {new_filename}")
|
||||
else:
|
||||
app.logger.warning(f"Book cover not found locally or in GridFS: {book_cover_image}")
|
||||
except Exception as e:
|
||||
app.logger.error(f"Error processing book cover {book_cover_image}: {str(e)}")
|
||||
|
||||
# 3. Item-Erstellung (Logik bleibt identisch, da it.add_item nun die GridFS-Filenames erhält)
|
||||
predefined_locations = it.get_predefined_locations()
|
||||
if ort and ort not in predefined_locations:
|
||||
it.add_predefined_location(ort)
|
||||
|
||||
reservierbar = 'reservierbar' in request.form
|
||||
|
||||
# Add one or more own items; sub-items are hidden in overview and counted on parent.
|
||||
reservierbar = 'reservierbar' in request.form
|
||||
created_item_ids = []
|
||||
series_group_id = str(uuid.uuid4()) if item_count > 1 else None
|
||||
base_code = code_4[0] if code_4 else None
|
||||
@@ -6096,6 +5598,8 @@ def upload_item():
|
||||
return redirect(url_for(success_redirect_endpoint))
|
||||
|
||||
parent_item_id = str(created_item_ids[0]) if created_item_ids else None
|
||||
|
||||
# image_filenames enthält jetzt ausschließlich GridFS-Filenames (oder ObjectIds, je nach deinem Setup)
|
||||
item_id = it.add_item(
|
||||
name, ort, beschreibung, image_filenames, filter_upload,
|
||||
filter_upload2, filter_upload3,
|
||||
@@ -6125,11 +5629,10 @@ def upload_item():
|
||||
return redirect(url_for(success_redirect_endpoint))
|
||||
|
||||
item_id = created_item_ids[0] if created_item_ids else None
|
||||
|
||||
|
||||
if item_id:
|
||||
# Create QR code for the item (deactivated)
|
||||
# create_qr_code(str(item_id))
|
||||
success_msg = f'Element wurde erfolgreich hinzugefügt ({len(created_item_ids)} erstellt)'
|
||||
|
||||
if upload_mode == 'library':
|
||||
try:
|
||||
_append_audit_event_standalone(
|
||||
@@ -6145,7 +5648,6 @@ def upload_item():
|
||||
except Exception:
|
||||
app.logger.warning('Audit write failed for library_item_created')
|
||||
|
||||
|
||||
flash(success_msg, 'success')
|
||||
return redirect(url_for(success_redirect_endpoint, highlight_item=str(item_id)))
|
||||
else:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user