cleanup: remove Excel test files, update COMPLETION.md for v3.0
Some checks failed
Build & Push Docker / build (push) Has been cancelled
Some checks failed
Build & Push Docker / build (push) Has been cancelled
This commit is contained in:
382
COMPLETION.md
382
COMPLETION.md
@@ -1,359 +1,37 @@
|
|||||||
# ✅ Scenar Creator — Refactoring & Features Complete
|
# ✅ Scenar Creator — v3.0 Complete
|
||||||
|
|
||||||
## Shrnutí dokončené práce
|
## Co je v3.0
|
||||||
|
|
||||||
Projekt byl úspěšně refaktorován, otestován a nyní podporuje:
|
Kompletní přepis aplikace. Žádný Excel, žádný CGI/Apache.
|
||||||
|
|
||||||
### 🎯 Nové Features
|
### Stack
|
||||||
|
- **Backend:** FastAPI + Uvicorn + ReportLab
|
||||||
|
- **Frontend:** Vanilla JS + interact.js (drag-and-drop canvas)
|
||||||
|
- **Data:** JSON import/export (bez Excelu)
|
||||||
|
- **Output:** PDF timetable (A4 landscape, barvy, legenda)
|
||||||
|
|
||||||
1. **Inline Excel Editor** — Webový formulář s JavaScript row management
|
### Features
|
||||||
- Přidávání/odstraňování řádků programu (`+` / `Smazat`)
|
1. **Canvas editor** — bloky na časové ose, přetahování myší, snap na 15 min, resize
|
||||||
- Přidávání/odstraňování typů programu
|
2. **JSON import/export** — uložte a načtěte scénář jako .json soubor
|
||||||
- Fullcolor picker pro barvy
|
3. **Vzorový JSON** — GET /api/sample pro šablonu
|
||||||
- Validace při submission
|
4. **PDF generátor** — ReportLab, barevné bloky dle typů, legenda, datum
|
||||||
|
5. **Dokumentace** — záložka "Dokumentace" přímo v aplikaci
|
||||||
|
6. **API docs** — GET /docs (Swagger UI)
|
||||||
|
|
||||||
2. **Refactored Architecture** — Business logic oddělená od CGI
|
### Endpoints
|
||||||
- `scenar/core.py` — 491 řádků čistého Python kódu (bez CGI/HTTP)
|
- `GET /` — hlavní UI
|
||||||
- `cgi-bin/scenar.py` — 450 řádků CGI wrapper + HTML rendering
|
- `GET /api/health` — health check (vrací verzi)
|
||||||
- Custom exceptions: `ScenarsError`, `ValidationError`, `TemplateError`
|
- `GET /api/sample` — vzorový JSON ke stažení
|
||||||
|
- `POST /api/validate` — validace ScenarioDocument
|
||||||
|
- `POST /api/generate-pdf` — vygeneruje PDF
|
||||||
|
|
||||||
3. **Kompletní Test Coverage** — 10 testů, všechny ✅ procházejí
|
### JSON formát
|
||||||
- 5 jednostkových testů pro core logiku
|
```json
|
||||||
- 4 testy pro inline editor (schedule + types parsing)
|
{
|
||||||
- 1 integrace test (Docker/Podman build + HTTP)
|
"version": "1.0",
|
||||||
|
"event": { "title": "...", "subtitle": "...", "date": "YYYY-MM-DD", "location": "..." },
|
||||||
### 📁 Nové/Upravené Soubory
|
"program_types": [{ "id": "...", "name": "...", "color": "#RRGGBB" }],
|
||||||
|
"blocks": [{ "id": "...", "date": "YYYY-MM-DD", "start": "HH:MM", "end": "HH:MM",
|
||||||
#### Nové soubory
|
"title": "...", "type_id": "...", "responsible": "...", "notes": "..." }]
|
||||||
|
}
|
||||||
```
|
```
|
||||||
scenar/__init__.py (package init)
|
|
||||||
scenar/core.py (491 řádků — business logic)
|
|
||||||
scripts/build_image.sh (Podman build helper)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Upravené soubory
|
|
||||||
```
|
|
||||||
Dockerfile (+ COPY scenar/ + pip install -r)
|
|
||||||
cgi-bin/scenar.py (450 řádků, import z scenar.core)
|
|
||||||
tests/test_read_excel.py (9 testů — Excel + inline)
|
|
||||||
tests/test_docker_integration.py (Podman integration)
|
|
||||||
requirements.txt (openpyxl==3.1.5 fix)
|
|
||||||
README.md (+ inline editor workflow)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Jak funguje nový kód
|
|
||||||
|
|
||||||
### Krok 1: Import → Validace → Parsování
|
|
||||||
|
|
||||||
**Import z Excelu:**
|
|
||||||
1. Uživatel uploaduje `*.xlsx` (step=2)
|
|
||||||
2. `read_excel()` parsuje a detekuje overlappy
|
|
||||||
3. `get_program_types()` extrahuje unikátní typy
|
|
||||||
4. Formulář v step=2 nabídne zadání barvy a popisu pro každý typ
|
|
||||||
|
|
||||||
**Inline Editor:**
|
|
||||||
1. Uživatel vyplní tabelu řádkami (step=builder)
|
|
||||||
2. JavaScript: `addScheduleRow()` / `removeScheduleRow()` manipulují DOM
|
|
||||||
3. `parse_inline_schedule()` validuje vstupní data
|
|
||||||
4. `parse_inline_types()` extrahuje definice typů z formuláře
|
|
||||||
|
|
||||||
### Krok 2: Generování Timetablu
|
|
||||||
|
|
||||||
```python
|
|
||||||
# oba workflow vedou k:
|
|
||||||
wb = create_timetable(
|
|
||||||
data, # DataFrame s programem
|
|
||||||
title, detail,
|
|
||||||
program_descriptions, # {typ: popis}
|
|
||||||
program_colors # {typ: AARRGGBB}
|
|
||||||
)
|
|
||||||
wb.save(file_path) # Excel soubor
|
|
||||||
```
|
|
||||||
|
|
||||||
Výstup: Profesionální Excel timetable s:
|
|
||||||
- Nadpis + detail v záhlaví
|
|
||||||
- Datum × Čas tabulka s programy
|
|
||||||
- Barevné výraznění typů
|
|
||||||
- Legenda s popisem typů
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 Test Coverage
|
|
||||||
|
|
||||||
### Unit Tests (9 testů)
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ test_read_excel_happy_path — Excel parsing s validními daty
|
|
||||||
✅ test_read_excel_invalid_time — Chyba na neplatný čas
|
|
||||||
✅ test_get_program_types — Extrakce typů ze formuláře
|
|
||||||
✅ test_create_timetable — Generování Excelu
|
|
||||||
✅ test_create_timetable_with_color_dict — Timetable s vlastními barvami
|
|
||||||
✅ test_parse_inline_schedule — Parsing inline řádků (9 řádků)
|
|
||||||
✅ test_parse_inline_schedule_missing — Validace povinných polí
|
|
||||||
✅ test_parse_inline_types — Parsing definic typů
|
|
||||||
✅ test_inline_workflow_integration — End-to-end: form → Excel
|
|
||||||
```
|
|
||||||
|
|
||||||
### Integration Test (1 test)
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ test_build_run_and_cleanup_podman — Build image, run container, HTTP test, cleanup
|
|
||||||
```
|
|
||||||
|
|
||||||
**Spuštění:**
|
|
||||||
```bash
|
|
||||||
# Všechny testy
|
|
||||||
pytest -v # 10/10 ✅
|
|
||||||
|
|
||||||
# Jen unit testy (bez Podman)
|
|
||||||
pytest -q -m "not integration" # 9/9 ✅
|
|
||||||
|
|
||||||
# Specifický test
|
|
||||||
pytest tests/test_read_excel.py::test_parse_inline_schedule -v
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Key Changes Detail
|
|
||||||
|
|
||||||
### `scenar/core.py` (NEW — 491 řádků)
|
|
||||||
|
|
||||||
**Funkce:**
|
|
||||||
- `read_excel(file_content)` → (valid_df, error_rows)
|
|
||||||
- `create_timetable(data, title, detail, descriptions, colors)` → Workbook
|
|
||||||
- `get_program_types(form_data)` → (descriptions, colors) tuple
|
|
||||||
- `validate_inputs(title, detail, file_size)` — Kontrola bezpečnosti
|
|
||||||
- `parse_inline_schedule(form)` → DataFrame (NOVÉ)
|
|
||||||
- `parse_inline_types(form)` → (descriptions, colors) tuple (NOVÉ)
|
|
||||||
|
|
||||||
**Custom Exceptions:**
|
|
||||||
```python
|
|
||||||
class ScenarsError(Exception): # Base
|
|
||||||
class ValidationError(ScenarsError): # Validační chyby
|
|
||||||
class TemplateError(ScenarsError): # Excel struktura
|
|
||||||
```
|
|
||||||
|
|
||||||
**Helpers:**
|
|
||||||
- `normalize_time()` — Parse HH:MM nebo HH:MM:SS
|
|
||||||
- `calculate_row_height()` — Auto-sizing řádků
|
|
||||||
- `calculate_column_width()` — Auto-sizing sloupců
|
|
||||||
- `validate_excel_template()` — Kontrola sloupců
|
|
||||||
|
|
||||||
### `cgi-bin/scenar.py` (REFACTORED — 450 řádků)
|
|
||||||
|
|
||||||
**Nově:**
|
|
||||||
```python
|
|
||||||
# sys.path fallback pro CGI kontext
|
|
||||||
import sys
|
|
||||||
if DOCROOT not in sys.path:
|
|
||||||
sys.path.insert(0, DOCROOT)
|
|
||||||
|
|
||||||
from scenar.core import read_excel, create_timetable, ...
|
|
||||||
```
|
|
||||||
|
|
||||||
**HTML Tabs:**
|
|
||||||
- Tab 1: "Importovat Excel" — klasický workflow
|
|
||||||
- Tab 2: "Vytvořit inline" — nový JS editor (NOVÝ)
|
|
||||||
|
|
||||||
**JavaScript Functions:**
|
|
||||||
```javascript
|
|
||||||
addScheduleRow() // Přidá řádek v tabulce
|
|
||||||
removeScheduleRow(id) // Smaže řádek
|
|
||||||
addTypeRow() // Přidá def. typu
|
|
||||||
removeTypeRow(id) // Smaže def. typu
|
|
||||||
switchTab(e, tabId) // Tab switching
|
|
||||||
```
|
|
||||||
|
|
||||||
**HTTP Handlers:**
|
|
||||||
- `step='1'` — Render home (import + inline tabs)
|
|
||||||
- `step='2'` — Load Excel, show type input form
|
|
||||||
- `step='3'` — Generate timetable (Excel import workflow)
|
|
||||||
- `step='builder'` — Generate from inline data (NOVÝ)
|
|
||||||
|
|
||||||
### `Dockerfile` (FIXED)
|
|
||||||
|
|
||||||
**Změny:**
|
|
||||||
```dockerfile
|
|
||||||
# Přidat scenar package do kontejneru
|
|
||||||
COPY scenar ./scenar
|
|
||||||
COPY requirements.txt ./requirements.txt
|
|
||||||
|
|
||||||
# Usar requirements.txt místo hardcodované verze
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Výsledek:** Container má přístup k `scenar.core` při CGI spuštění
|
|
||||||
|
|
||||||
### `requirements.txt` (FIXED)
|
|
||||||
|
|
||||||
```
|
|
||||||
pandas==2.1.3
|
|
||||||
openpyxl==3.1.5 # Byla 3.11.0 (neexistuje!) → Fixed
|
|
||||||
pytest==7.4.3
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Workflow Diagrams
|
|
||||||
|
|
||||||
### Import Excel Workflow
|
|
||||||
```
|
|
||||||
Home (step=1)
|
|
||||||
↓ upload file
|
|
||||||
Step 2: Load Excel → Detect Types
|
|
||||||
↓ fill descriptions + colors
|
|
||||||
Step 3: Generate Timetable
|
|
||||||
↓ Download Excel
|
|
||||||
Done ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
### Inline Editor Workflow
|
|
||||||
```
|
|
||||||
Home (step=1)
|
|
||||||
↓ click "Vytvořit inline" tab
|
|
||||||
Fill Form + JS Row Management
|
|
||||||
↓ submit (step=builder)
|
|
||||||
Parse Form → Generate Timetable
|
|
||||||
↓ Download Excel
|
|
||||||
Done ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔍 Validation Logic
|
|
||||||
|
|
||||||
### Input Validation
|
|
||||||
```python
|
|
||||||
validate_inputs(title, detail, file_size)
|
|
||||||
# Checks:
|
|
||||||
# - title: required, 1-200 chars
|
|
||||||
# - detail: required, 1-500 chars
|
|
||||||
# - file_size: max 10 MB
|
|
||||||
```
|
|
||||||
|
|
||||||
### Excel Parsing
|
|
||||||
```python
|
|
||||||
read_excel(file_content)
|
|
||||||
# Checks:
|
|
||||||
# - Required columns: Datum, Zacatek, Konec, Program, Typ, Garant, Poznamka
|
|
||||||
# - Date format: YYYY-MM-DD
|
|
||||||
# - Time format: HH:MM or HH:MM:SS
|
|
||||||
# - Time overlaps: Detects and errors
|
|
||||||
# Returns: (valid_data, error_rows)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Inline Schedule Parsing
|
|
||||||
```python
|
|
||||||
parse_inline_schedule(form)
|
|
||||||
# Checks:
|
|
||||||
# - Each row: all required fields filled
|
|
||||||
# - Dates valid (YYYY-MM-DD)
|
|
||||||
# - Times valid (HH:MM or HH:MM:SS)
|
|
||||||
# - Skips empty rows
|
|
||||||
# Raises: ValidationError if invalid
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐳 Container & Deployment
|
|
||||||
|
|
||||||
### Local Testing (bez Dockeru)
|
|
||||||
```bash
|
|
||||||
python -m http.server --cgi 8000
|
|
||||||
# http://localhost:8000/cgi-bin/scenar.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### Podman/Docker (produkce)
|
|
||||||
```bash
|
|
||||||
# Build
|
|
||||||
podman build -t scenar-creator:latest .
|
|
||||||
|
|
||||||
# Run
|
|
||||||
podman run -d -p 8080:8080 \
|
|
||||||
-v $(pwd)/tmp:/var/www/htdocs/tmp \
|
|
||||||
scenar-creator:latest
|
|
||||||
|
|
||||||
# Visit: http://localhost:8080/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pre-commit Hooks
|
|
||||||
```bash
|
|
||||||
./scripts/install_hooks.sh
|
|
||||||
git commit -m "..." # Runs pytest automatically
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Architecture Summary
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────┐
|
|
||||||
│ Browser (HTML + JavaScript) │
|
|
||||||
│ - Form: Title, Detail, File/Inline Data │
|
|
||||||
│ - JS: Row add/remove (DOM manipulation) │
|
|
||||||
└────────────────┬────────────────────────────────────┘
|
|
||||||
│ HTTP POST
|
|
||||||
┌────────────────▼────────────────────────────────────┐
|
|
||||||
│ cgi-bin/scenar.py (CGI Wrapper — 450 lines) │
|
|
||||||
│ - Form parsing (cgi.FieldStorage) │
|
|
||||||
│ - Step routing (1, 2, 3, builder) │
|
|
||||||
│ - HTML rendering │
|
|
||||||
│ - Imports from scenar.core │
|
|
||||||
└────────────────┬────────────────────────────────────┘
|
|
||||||
│
|
|
||||||
┌────────────────▼────────────────────────────────────┐
|
|
||||||
│ scenar/core.py (Business Logic — 491 lines) │
|
|
||||||
│ - read_excel() → validate & parse Excel │
|
|
||||||
│ - parse_inline_schedule() → validate form data │
|
|
||||||
│ - parse_inline_types() → extract type definitions│
|
|
||||||
│ - create_timetable() → generate OpenPyXL │
|
|
||||||
│ - Custom exceptions & validation │
|
|
||||||
└────────────────┬────────────────────────────────────┘
|
|
||||||
│
|
|
||||||
┌────────────────▼────────────────────────────────────┐
|
|
||||||
│ Dependencies: pandas, openpyxl, Python 3.12 │
|
|
||||||
│ Testing: pytest (9 units + 1 integration) │
|
|
||||||
│ Container: Podman/Docker (port 8080) │
|
|
||||||
└──────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✨ Highlights
|
|
||||||
|
|
||||||
- ✅ **No 500 errors** — sys.path fix + Dockerfile fix
|
|
||||||
- ✅ **Full test coverage** — 10 tests, all passing
|
|
||||||
- ✅ **Two workflows** — Excel import OR inline editor
|
|
||||||
- ✅ **JavaScript row management** — DOM manipulation for schedule/types
|
|
||||||
- ✅ **Professional Excel output** — Styling, colors, legend, auto-sizing
|
|
||||||
- ✅ **Clean architecture** — Core logic separated from CGI
|
|
||||||
- ✅ **Validated inputs** — Security checks for file size, string lengths
|
|
||||||
- ✅ **Comprehensive error handling** — Custom exceptions, user-friendly messages
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Next Steps (Optional Enhancements)
|
|
||||||
|
|
||||||
1. **Database** — Store scenarios in DB instead of tmp files
|
|
||||||
2. **Export to PDF** — Generate PDF instead of just Excel
|
|
||||||
3. **Collaborative editing** — Real-time sync between users
|
|
||||||
4. **Authentication** — User accounts & access control
|
|
||||||
5. **More type validation** — Email, phone numbers in Garant field
|
|
||||||
6. **Duplicate detection** — Warn if same program at same time
|
|
||||||
7. **Template library** — Save & reuse scenarios
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Documentation
|
|
||||||
|
|
||||||
- **README.md** — User guide + installation
|
|
||||||
- **`.github/copilot-instructions.md`** — AI agent instructions
|
|
||||||
- **This file** — Technical summary & architecture
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Date:** November 13, 2025
|
|
||||||
**Status:** ✅ **COMPLETE & TESTED**
|
|
||||||
**Test Result:** 10/10 ✅ passing
|
|
||||||
|
|||||||
Binary file not shown.
BIN
tmp/FAKAP.xlsx
BIN
tmp/FAKAP.xlsx
Binary file not shown.
BIN
tmp/FAKAP2.xlsx
BIN
tmp/FAKAP2.xlsx
Binary file not shown.
BIN
tmp/FAKAP3.xlsx
BIN
tmp/FAKAP3.xlsx
Binary file not shown.
BIN
tmp/TRABANT.xlsx
BIN
tmp/TRABANT.xlsx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tmp/a.xlsx
BIN
tmp/a.xlsx
Binary file not shown.
BIN
tmp/test.xlsx
BIN
tmp/test.xlsx
Binary file not shown.
BIN
tmp/x.xlsx
BIN
tmp/x.xlsx
Binary file not shown.
Reference in New Issue
Block a user