session_details.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import csv
  2. import xml.etree.ElementTree as ET
  3. from dataclasses import dataclass
  4. from datetime import datetime
  5. from pathlib import Path
  6. from clients import calculate_customer
  7. @dataclass(frozen=True)
  8. class SessionDetailsResult:
  9. xml_count: int
  10. activity_count: int
  11. def find_xml_files(directory: Path) -> list[Path]:
  12. return sorted(
  13. path
  14. for path in directory.rglob("*")
  15. if path.is_file() and path.suffix.lower() == ".xml" and not path.name.lower().startswith("sessions")
  16. )
  17. def extract_session_details(xml_path: Path) -> list[dict[str, str]]:
  18. try:
  19. root = ET.parse(xml_path).getroot()
  20. except ET.ParseError:
  21. return []
  22. session = root.find("Session")
  23. if session is None:
  24. return []
  25. client_description = session.find("SessionDescription[@Name='ClientName']")
  26. client_name = "" if client_description is None else client_description.get("Description", "")
  27. if not client_name.strip():
  28. return []
  29. customer = calculate_customer(client_name)
  30. activities = []
  31. for activity in session.findall("UserActivity"):
  32. date_time = activity.get("DateTime", "").strip()
  33. activity_type = activity.get("Type", "").strip()
  34. try:
  35. parsed_date_time = datetime.fromisoformat(date_time.replace("Z", "+00:00"))
  36. except ValueError:
  37. continue
  38. if date_time and activity_type:
  39. activities.append((parsed_date_time, date_time, activity_type))
  40. day_counts = {}
  41. for parsed_date_time, _, _ in activities:
  42. day_counts[parsed_date_time.date()] = day_counts.get(parsed_date_time.date(), 0) + 1
  43. rows = []
  44. for index, (parsed_date_time, date_time, activity_type) in enumerate(activities):
  45. next_date_time = activities[index + 1][0] if index + 1 < len(activities) else parsed_date_time
  46. duration = min(max(int((next_date_time - parsed_date_time).total_seconds()), 0), 900)
  47. if (
  48. len(day_counts) > 1
  49. and day_counts[parsed_date_time.date()] == 1
  50. and activity_type == "SupportAndPresentationMode"
  51. ):
  52. duration = 0
  53. rows.append(
  54. {
  55. "DateTime": date_time,
  56. "Kunde": customer,
  57. "UserActivityType": activity_type,
  58. "Duration": str(duration),
  59. }
  60. )
  61. return rows
  62. def write_session_details(rows: list[dict[str, str]], output: Path) -> None:
  63. output.parent.mkdir(parents=True, exist_ok=True)
  64. with output.open("w", newline="", encoding="latin-1", errors="replace") as csv_file:
  65. writer = csv.DictWriter(
  66. csv_file,
  67. fieldnames=["DateTime", "Kunde", "UserActivityType", "Duration"],
  68. delimiter=";",
  69. )
  70. writer.writeheader()
  71. writer.writerows(rows)
  72. def run(directory: Path, output: Path) -> SessionDetailsResult:
  73. if not directory.is_dir():
  74. raise ValueError(f"Das Verzeichnis existiert nicht: {directory}")
  75. xml_files = find_xml_files(directory)
  76. rows = [row for xml_file in xml_files for row in extract_session_details(xml_file)]
  77. rows.sort(key=lambda row: row["DateTime"])
  78. write_session_details(rows, output)
  79. return SessionDetailsResult(xml_count=len(xml_files), activity_count=len(rows))