mapping.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. # -*- coding: utf-8 -*-
  2. """
  3. Satellite-Calendar Mapper.
  4. Ordnet Satellites den konfigurierten Kalendern zu.
  5. Unterstuetzt Matching per Alias und Room-ID.
  6. """
  7. from trixy_core.utils.debug import pdebug
  8. from plugins.calendar.models import CalendarInfo
  9. class SatelliteCalendarMapper:
  10. """
  11. Verwaltet die Zuordnung zwischen Satellites und Kalendern.
  12. Matching-Logik:
  13. 1. Satellite-Alias oder Room-ID gegen konfigurierte Eintraege pruefen
  14. 2. Globale Kalender werden immer hinzugefuegt
  15. 3. Standalone-Modus: Fallback auf ersten Eintrag
  16. """
  17. def __init__(self, config: dict, application: object) -> None:
  18. """
  19. Args:
  20. config: Plugin-Konfiguration (komplett)
  21. application: Application-Instanz
  22. """
  23. self._config = config
  24. self._application = application
  25. self._satellite_mapping = config.get("satellite_mapping", {})
  26. self._calendars_config = config.get("calendars", {})
  27. self._global_calendars = self._satellite_mapping.get("global_calendars", [])
  28. self._entries = self._satellite_mapping.get("satellites", [])
  29. def get_calendars_for_satellite(self, satellite_id: str) -> list[CalendarInfo]:
  30. """
  31. Gibt alle Kalender fuer einen Satellite zurueck.
  32. Args:
  33. satellite_id: Satellite-ID
  34. Returns:
  35. Liste von CalendarInfo (persoenliche + globale Kalender)
  36. """
  37. entry = self._find_entry_for_satellite(satellite_id)
  38. calendar_keys: list[str] = []
  39. # Persoenliche Kalender
  40. if entry:
  41. calendar_keys.extend(entry.get("calendars", []))
  42. # Globale Kalender
  43. for key in self._global_calendars:
  44. if key not in calendar_keys:
  45. calendar_keys.append(key)
  46. return self._keys_to_infos(calendar_keys)
  47. def get_write_calendar(self, satellite_id: str) -> CalendarInfo | None:
  48. """
  49. Gibt den Standard-Schreib-Kalender fuer einen Satellite zurueck.
  50. Args:
  51. satellite_id: Satellite-ID
  52. Returns:
  53. CalendarInfo oder None
  54. """
  55. entry = self._find_entry_for_satellite(satellite_id)
  56. if not entry:
  57. return None
  58. write_key = entry.get("default_write_calendar", "")
  59. if not write_key:
  60. return None
  61. cal_config = self._calendars_config.get(write_key, {})
  62. if not cal_config:
  63. return None
  64. if cal_config.get("readonly", True):
  65. return None
  66. return CalendarInfo(
  67. calendar_id=cal_config.get("calendar_id", ""),
  68. provider_name=cal_config.get("provider", ""),
  69. display_name=cal_config.get("display_name", write_key),
  70. readonly=False,
  71. )
  72. def get_person_name(self, satellite_id: str) -> str:
  73. """
  74. Gibt den Personennamen fuer einen Satellite zurueck.
  75. Args:
  76. satellite_id: Satellite-ID
  77. Returns:
  78. Personenname oder leerer String
  79. """
  80. entry = self._find_entry_for_satellite(satellite_id)
  81. if entry:
  82. return entry.get("person_name", "")
  83. return ""
  84. def get_satellites_for_calendar(self, calendar_key: str) -> list[str]:
  85. """
  86. Gibt alle Satellite-IDs zurueck, die einen bestimmten Kalender sehen.
  87. Args:
  88. calendar_key: Kalender-Schluessel
  89. Returns:
  90. Liste von Satellite-IDs
  91. """
  92. satellite_ids: list[str] = []
  93. # Globaler Kalender: Alle Satellites
  94. if calendar_key in self._global_calendars:
  95. return self._get_all_satellite_ids()
  96. # Per Entry pruefen
  97. for entry in self._entries:
  98. if calendar_key in entry.get("calendars", []):
  99. ids = self._get_satellite_ids_for_entry(entry)
  100. satellite_ids.extend(ids)
  101. return satellite_ids
  102. def find_person_calendars(self, person_name: str) -> list[str]:
  103. """
  104. Findet Kalender-Keys fuer eine Person (z.B. "Wann hat André Zeit?").
  105. Args:
  106. person_name: Personenname
  107. Returns:
  108. Liste von Kalender-Keys
  109. """
  110. person_lower = person_name.lower()
  111. for entry in self._entries:
  112. entry_person = entry.get("person_name", "").lower()
  113. if entry_person == person_lower:
  114. return entry.get("calendars", [])
  115. return []
  116. def get_calendar_config(self, calendar_key: str) -> dict:
  117. """
  118. Gibt die Konfiguration eines Kalenders zurueck.
  119. Args:
  120. calendar_key: Kalender-Schluessel
  121. Returns:
  122. Kalender-Konfiguration
  123. """
  124. return self._calendars_config.get(calendar_key, {})
  125. # =========================================================================
  126. # Private Methoden
  127. # =========================================================================
  128. def _find_entry_for_satellite(self, satellite_id: str) -> dict | None:
  129. """Findet den Mapping-Eintrag fuer einen Satellite."""
  130. # Satellite-Daten holen
  131. satellites = getattr(self._application, "satellites", None)
  132. if not satellites:
  133. # Standalone-Modus: Ersten Eintrag als Fallback verwenden
  134. if self._entries:
  135. return self._entries[0]
  136. return None
  137. satellite = satellites.get(satellite_id)
  138. if not satellite:
  139. return None
  140. sat_alias = getattr(satellite, "alias", "").lower()
  141. sat_room = getattr(satellite, "room_id", "").lower()
  142. for entry in self._entries:
  143. # Alias-Matching
  144. alias_list = [a.strip().lower() for a in entry.get("alias", "").split(",")]
  145. if sat_alias and sat_alias in alias_list:
  146. return entry
  147. # Room-Matching
  148. room_list = [r.strip().lower() for r in entry.get("room", "").split(",")]
  149. if sat_room and sat_room in room_list:
  150. return entry
  151. return None
  152. def _get_satellite_ids_for_entry(self, entry: dict) -> list[str]:
  153. """Gibt alle Satellite-IDs zurueck, die zu einem Eintrag passen."""
  154. satellites = getattr(self._application, "satellites", None)
  155. if not satellites:
  156. return []
  157. ids: list[str] = []
  158. alias_list = [a.strip().lower() for a in entry.get("alias", "").split(",")]
  159. room_list = [r.strip().lower() for r in entry.get("room", "").split(",")]
  160. for sat in satellites:
  161. sat_alias = getattr(sat, "alias", "").lower()
  162. sat_room = getattr(sat, "room_id", "").lower()
  163. if (sat_alias and sat_alias in alias_list) or (sat_room and sat_room in room_list):
  164. ids.append(sat.id)
  165. return ids
  166. def _get_all_satellite_ids(self) -> list[str]:
  167. """Gibt alle verbundenen Satellite-IDs zurueck."""
  168. satellites = getattr(self._application, "satellites", None)
  169. if not satellites:
  170. return []
  171. return [sat.id for sat in satellites if sat.is_connected]
  172. def _keys_to_infos(self, calendar_keys: list[str]) -> list[CalendarInfo]:
  173. """Konvertiert Kalender-Keys in CalendarInfo-Objekte."""
  174. infos: list[CalendarInfo] = []
  175. for key in calendar_keys:
  176. cal_config = self._calendars_config.get(key, {})
  177. if not cal_config:
  178. continue
  179. infos.append(CalendarInfo(
  180. calendar_id=cal_config.get("calendar_id", ""),
  181. provider_name=cal_config.get("provider", ""),
  182. display_name=cal_config.get("display_name", key),
  183. readonly=cal_config.get("readonly", True),
  184. is_global=key in self._global_calendars,
  185. ))
  186. return infos