Files
scenar-creator/scenar.py
Charlie Root aedb654ef4 scenar
2025-11-06 14:22:51 +01:00

197 lines
7.7 KiB
Python
Executable File

#!/usr/bin/env python3
import cgi
import cgitb
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
from openpyxl.utils import get_column_letter
from datetime import datetime
from io import StringIO
import os
import shutil
cgitb.enable()
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
title = form.getvalue('title')
detail = form.getvalue('detail')
csv_content = form.getvalue('csv_content')
program_descriptions = {
"C": form.getvalue('desc_C', "Program naplnujici cile"),
"S": form.getvalue('desc_S', "Program pro podporu skupinove dynamiky"),
"K": form.getvalue('desc_K', "Kreativni program"),
"P": form.getvalue('desc_P', "Provozni blok"),
"O": form.getvalue('desc_O', "Vyplnove a ostatni programy"),
}
program_colors = {
"C": 'FF' + form.getvalue('color_C', "ADD8E6").lstrip('#'),
"S": 'FF' + form.getvalue('color_S', "90EE90").lstrip('#'),
"K": 'FF' + form.getvalue('color_K', "FFFF00").lstrip('#'),
"P": 'FF' + form.getvalue('color_P', "D3D3D3").lstrip('#'),
"O": 'FF' + form.getvalue('color_O', "FFB6C1").lstrip('#'),
}
def read_csv_from_string(csv_string):
return pd.read_csv(StringIO(csv_string), sep=";", header=None, names=["Datum", "Zacatek", "Konec", "Program", "Typ", "Garant", "Poznamka"])
def calculate_row_height(cell_value, column_width):
if not cell_value:
return 15
max_line_length = column_width * 1.2
lines = cell_value.split('\n')
line_count = 0
for line in lines:
line_count += len(line) // max_line_length + 1
return line_count * 15
def create_timetable(data, title, detail, program_descriptions, program_colors):
wb = Workbook()
ws = wb.active
thick_border = Border(left=Side(style='thick', color='000000'),
right=Side(style='thick', color='000000'),
top=Side(style='thick', color='000000'),
bottom=Side(style='thick', color='000000'))
ws['A1'] = title
ws['A1'].alignment = Alignment(horizontal="center", vertical="center")
ws['A1'].font = Font(size=24, bold=True)
ws['A1'].border = thick_border
ws['A2'] = detail
ws['A2'].alignment = Alignment(horizontal="center", vertical="center")
ws['A2'].font = Font(size=16, italic=True)
ws['A2'].border = thick_border
# Nastavení výšky řádků pro nadpis a podnadpis
title_row_height = calculate_row_height(title, ws.column_dimensions[get_column_letter(1)].width)
detail_row_height = calculate_row_height(detail, ws.column_dimensions[get_column_letter(1)].width)
ws.row_dimensions[1].height = title_row_height
ws.row_dimensions[2].height = detail_row_height
data["Datum"] = pd.to_datetime(data["Datum"], format="%d.%m.%Y")
data = data.sort_values(by=["Datum", "Zacatek"])
start_times = data["Zacatek"].apply(lambda x: datetime.strptime(str(x), '%H%M'))
end_times = data["Konec"].apply(lambda x: datetime.strptime(str(x), '%H%M'))
min_time = start_times.min()
max_time = end_times.max()
time_slots = pd.date_range(min_time, max_time, freq='15min').time
total_columns = len(time_slots) + 1
ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=total_columns)
ws.merge_cells(start_row=2, start_column=1, end_row=2, end_column=total_columns)
row_offset = 3
col_offset = 1
cell = ws.cell(row=row_offset, column=col_offset, value="Datum")
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.border = thick_border
for i, time_slot in enumerate(time_slots, start=col_offset + 1):
cell = ws.cell(row=row_offset, column=i, value=time_slot.strftime("%H:%M"))
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.font = Font(bold=True)
cell.border = thick_border
current_row = row_offset + 1
grouped_data = data.groupby(data['Datum'])
for date, group in grouped_data:
day_name = date.strftime("%A")
date_str = date.strftime(f"%d.%m {day_name}")
cell = ws.cell(row=current_row, column=col_offset, value=date_str)
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
cell.font = Font(bold=True, size=14)
cell.border = thick_border
for _, row in group.iterrows():
start_time = datetime.strptime(str(row["Zacatek"]), '%H%M').time()
end_time = datetime.strptime(str(row["Konec"]), '%H%M').time()
start_index = list(time_slots).index(start_time) + col_offset + 1
end_index = list(time_slots).index(end_time) + col_offset + 1
cell_value = f"{row['Program']}"
if pd.notna(row['Garant']):
cell_value += f"\n{row['Garant']}"
if pd.notna(row['Poznamka']):
cell_value += f"\n\n{row['Poznamka']}"
ws.merge_cells(start_row=current_row, start_column=start_index, end_row=current_row, end_column=end_index - 1)
cell = ws.cell(row=current_row, column=start_index)
cell.value = cell_value
cell.alignment = Alignment(wrap_text=True, horizontal="center", vertical="center")
lines = cell_value.split("\n")
for idx, line in enumerate(lines):
if idx == 0:
cell.font = Font(bold=True)
elif idx == 1:
cell.font = Font(bold=False)
elif idx > 1 and pd.notna(row['Poznamka']):
cell.font = Font(italic=True)
cell.fill = PatternFill(start_color=program_colors[row["Typ"]], end_color=program_colors[row["Typ"]], fill_type="solid")
cell.border = thick_border
current_row += 1
legend_row = current_row + 2
legend_max_length = 0
ws.cell(row=legend_row, column=1, value="Legenda:").font = Font(bold=True)
legend_row += 1
for typ, desc in program_descriptions.items():
legend_text = f"{desc} ({typ})"
legend_cell = ws.cell(row=legend_row, column=1, value=legend_text)
legend_cell.fill = PatternFill(start_color=program_colors[typ], fill_type="solid")
legend_max_length = max(legend_max_length, calculate_column_width(legend_text))
legend_row += 1
ws.column_dimensions[get_column_letter(col_offset)].width = legend_max_length
for col in range(2, total_columns + 1):
ws.column_dimensions[get_column_letter(col)].width = 15
for row in ws.iter_rows(min_row=1, max_row=current_row - 1, min_col=1, max_col=total_columns):
for cell in row:
cell.alignment = Alignment(wrap_text=True, horizontal="center", vertical="center")
cell.border = thick_border
for row in ws.iter_rows(min_row=1, max_row=current_row - 1):
max_height = 0
for cell in row:
if cell.value:
height = calculate_row_height(cell.value, ws.column_dimensions[get_column_letter(cell.column)].width)
if height > max_height:
max_height = height
ws.row_dimensions[row[0].row].height = max_height
return wb
def calculate_column_width(text):
max_length = max(len(line) for line in text.split('\n'))
return max_length * 1.2
data = read_csv_from_string(csv_content)
wb = create_timetable(data, title, detail, program_descriptions, program_colors)
filename = f"{title}.xlsx"
file_path = f"/var/www/htdocs/{filename}"
wb.save(file_path)
print(f'<a href="/{filename}" download>Stahnout scenar pro {title} ZDE</a>')