From 2f4c9307395ca083b6ca5f4b21df8d574a9963de Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Thu, 13 Nov 2025 16:15:23 +0100 Subject: [PATCH] Fix: step 2 -> step 2b/3 workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: - Když uživatel importoval Excel a klikl 'Upravit v inline editoru' nebo 'Generovat', dostal chybu 'Neplatný krok nebo chybějící data' - step 2b vyžadoval file_item, ale formulář posílal file_content_base64 Řešení: - Upravena podmínka pro step=2b aby akceptovala i file_content_base64 - Přidány 2 nové testy: * test_excel_import_to_step2_workflow - testuje import -> step 2 -> step 3 (generate) * test_excel_import_to_inline_editor_workflow - testuje import -> step 2 -> step 2b (inline editor) Testy: 18/18 unit testů prošlo ✅ --- cgi-bin/scenar.py | 27 +++++++--- tests/test_read_excel.py | 110 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 8 deletions(-) diff --git a/cgi-bin/scenar.py b/cgi-bin/scenar.py index 2ae33eb..a9723b0 100755 --- a/cgi-bin/scenar.py +++ b/cgi-bin/scenar.py @@ -583,17 +583,28 @@ button:hover { background: #0056b3; } logger.error(f"Unexpected error: {str(e)}") render_error(f"Neočekávaná chyba: {str(e)}") -elif step == '2b' and file_item is not None and file_item.filename: +elif step == '2b': """Load Excel data into inline editor for editing.""" try: - file_content = file_item.file.read() - file_size = len(file_content) + # Get file content from either file upload or base64 + file_content = None + if file_item is not None and file_item.filename: + file_content = file_item.file.read() + else: + file_content_base64 = form.getvalue('file_content_base64', '') + if file_content_base64: + file_content = base64.b64decode(file_content_base64) - # Validate inputs - validate_inputs(title, detail, file_size) - - # Read Excel - data, error_rows = read_excel(file_content, show_debug) + if not file_content: + render_error("Chyba: Soubor nebyl nalezen.") + else: + file_size = len(file_content) + + # Validate inputs + validate_inputs(title, detail, file_size) + + # Read Excel + data, error_rows = read_excel(file_content, show_debug) if data.empty: render_error("Načtená data jsou prázdná nebo obsahují neplatné hodnoty. Zkontrolujte vstupní soubor.") diff --git a/tests/test_read_excel.py b/tests/test_read_excel.py index 154f9e4..b3ed295 100644 --- a/tests/test_read_excel.py +++ b/tests/test_read_excel.py @@ -249,3 +249,113 @@ def test_inline_workflow_integration(): ws = wb.active assert ws['A1'].value == "Integration Test Event" assert ws['A2'].value == "Testing inline workflow" + + +def test_excel_import_to_step2_workflow(): + """Test workflow: Excel import -> step 2 (type definition) -> step 3 (generate). + This simulates the user uploading Excel, then filling type definitions. + """ + import base64 + + # Step 1: Create Excel file + df = pd.DataFrame({ + 'Datum': [pd.Timestamp('2025-11-13').date()], + 'Zacatek': ['09:00'], + 'Konec': ['10:00'], + 'Program': ['Opening Keynote'], + 'Typ': ['KEYNOTE'], + 'Garant': ['John Smith'], + 'Poznamka': ['Welcome speech'] + }) + + file_content = make_excel_bytes(df) + + # Step 2: Read Excel (simulating step=2 processing) + valid_data, errors = read_excel(file_content) + assert len(errors) == 0 + assert len(valid_data) == 1 + + # Extract types + program_types = sorted([str(t).strip() for t in valid_data["Typ"].dropna().unique()]) + assert program_types == ['KEYNOTE'] + + # Step 3: User fills type definitions (simulating form submission in step=2) + # This would be base64 encoded in the hidden field + file_content_base64 = base64.b64encode(file_content).decode('utf-8') + + form_data = { + 'title': 'Test Event', + 'detail': 'Test Detail', + 'file_content_base64': file_content_base64, + 'type_code_0': 'KEYNOTE', + 'desc_0': 'Main keynote presentation', + 'color_0': '#FF0000', + 'step': '3' + } + + # Parse types (simulating step=3 processing) + descriptions, colors = get_program_types(form_data) + + assert descriptions['KEYNOTE'] == 'Main keynote presentation' + assert colors['KEYNOTE'] == 'FFFF0000' + + # Step 4: Generate timetable + # Re-read Excel from base64 + file_content_decoded = base64.b64decode(form_data['file_content_base64']) + data, _ = read_excel(file_content_decoded) + + wb = create_timetable( + data, + title=form_data['title'], + detail=form_data['detail'], + program_descriptions=descriptions, + program_colors=colors + ) + + assert wb is not None + ws = wb.active + assert ws['A1'].value == 'Test Event' + assert ws['A2'].value == 'Test Detail' + + +def test_excel_import_to_inline_editor_workflow(): + """Test workflow: Excel import -> step 2 -> step 2b (inline editor). + This simulates clicking 'Upravit v inline editoru' button. + """ + import base64 + + # Create Excel file + df = pd.DataFrame({ + 'Datum': [pd.Timestamp('2025-11-13').date(), pd.Timestamp('2025-11-14').date()], + 'Zacatek': ['09:00', '14:00'], + 'Konec': ['10:00', '15:30'], + 'Program': ['Morning Session', 'Afternoon Workshop'], + 'Typ': ['KEYNOTE', 'WORKSHOP'], + 'Garant': ['Alice', 'Bob'], + 'Poznamka': ['', 'Hands-on'] + }) + + file_content = make_excel_bytes(df) + + # Step 2: Read Excel + valid_data, errors = read_excel(file_content) + assert len(errors) == 0 + assert len(valid_data) == 2 + + # Step 2b: User clicks "Upravit v inline editoru" + # The form would pass file_content_base64 to step=2b + file_content_base64 = base64.b64encode(file_content).decode('utf-8') + + # Simulate step 2b: decode and re-read Excel + file_content_decoded = base64.b64decode(file_content_base64) + data_in_editor, _ = read_excel(file_content_decoded) + + # Verify data loaded correctly + assert len(data_in_editor) == 2 + assert data_in_editor.iloc[0]['Program'] == 'Morning Session' + assert data_in_editor.iloc[1]['Program'] == 'Afternoon Workshop' + + # Extract types for editor + program_types = sorted([str(t).strip() for t in data_in_editor["Typ"].dropna().unique()]) + assert set(program_types) == {'KEYNOTE', 'WORKSHOP'} +