prepareData.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import datetime
  2. from typing import List, Tuple
  3. import ics
  4. from uuid import uuid4
  5. import pandas as pd
  6. from jinja2 import Environment, FileSystemLoader, select_autoescape
  7. PROGRAM_UID = "a1799f64-f93c-48f1-bcf6-0e5619c9410c"
  8. BENEVOLE_SEPARATOR = "\n - "
  9. ALARM_DELTA = datetime.timedelta(minutes=-30)
  10. JINJA_ENV = Environment(
  11. loader=FileSystemLoader("templates"), autoescape=select_autoescape()
  12. )
  13. def getContactList(benevole_names: List[str], df_contact) -> List[str]:
  14. if len(benevole_names) == 0:
  15. return []
  16. filtered_contact = df_contact[df_contact["Prénom"].isin(benevole_names)]
  17. arr = filtered_contact.apply(
  18. lambda item: f"{item['Prénom']} : {item['Tél']}", axis=1
  19. )
  20. if len(arr) != len(benevole_names):
  21. print("Missing names from", benevole_names)
  22. return []
  23. return arr.to_list()
  24. class Slot(object):
  25. def __init__(
  26. self,
  27. name: str,
  28. description: str,
  29. start: datetime.datetime,
  30. end: datetime.datetime,
  31. location: str,
  32. responsable: str,
  33. starting_with_you: List[str] = [],
  34. benevole_you_replace: List[str] = [],
  35. benevole_following_you: List[str] = [],
  36. ):
  37. self.name = name
  38. self.description = description
  39. self.start = start
  40. self.end = end
  41. self.location = location
  42. self.responsable = responsable
  43. self.starting_with_you = starting_with_you
  44. self.benevole_you_replace = benevole_you_replace
  45. self.benevole_following_you = benevole_following_you
  46. @property
  47. def horaire(self):
  48. return self.start.strftime("%Hh%M") + "-" + self.end.strftime("%Hh%M")
  49. @property
  50. def day(self):
  51. return (self.start - datetime.timedelta(hours=5)).date()
  52. @property
  53. def alarm_time(self):
  54. return self.start + ALARM_DELTA
  55. def toIEvent(self) -> ics.Event:
  56. description = f"{self.description}\n\nResponsable à contacter en cas de problème : {self.responsable}"
  57. if len(self.starting_with_you) > 0:
  58. description += (
  59. "\n\nLes bénévoles avec qui tu sera : "
  60. + BENEVOLE_SEPARATOR.join(["", *self.starting_with_you])
  61. )
  62. if len(self.benevole_you_replace) > 0:
  63. description += (
  64. "\n\nLes bénévoles que tu remplaces : "
  65. + BENEVOLE_SEPARATOR.join(["", *self.benevole_you_replace])
  66. )
  67. if len(self.benevole_following_you) > 0:
  68. description += (
  69. "\n\nLes personnes qui arrivent après toi : "
  70. + BENEVOLE_SEPARATOR.join(["", *self.benevole_following_you])
  71. )
  72. alarms = [ics.AudioAlarm(ALARM_DELTA), ics.DisplayAlarm(ALARM_DELTA)]
  73. return ics.Event(
  74. name=f"[BDLG] {self.name}",
  75. begin=self.start,
  76. end=self.end,
  77. description=description,
  78. location=self.location,
  79. alarms=alarms,
  80. )
  81. def toHTML(self) -> str:
  82. return JINJA_ENV.get_template("Creneau.html").render(slot=self)
  83. def toReminderText(self) -> str:
  84. return (
  85. "Votre prochain créneau bénévole BDLG commence bientôt!\n"
  86. + f"Nom de créneau : {self.name}\n"
  87. + f"Début : {self.start.strftime('%Hh%M')}"
  88. )
  89. def __repr__(self) -> str:
  90. return (
  91. f"<Slot name={self.name} start={self.start.ctime()} end={self.end.ctime()}>"
  92. )
  93. def getSlots(
  94. username: str, df_planning, df_contact: pd.DataFrame, df_creneau: pd.DataFrame
  95. ) -> List[Slot]:
  96. df = df_planning
  97. arr = []
  98. for row, item in df[df.benevole_nom == username].iterrows():
  99. starting_with_you = df.benevole_nom[
  100. (df.nom == item.nom)
  101. & (df.start == item.start)
  102. & (df.benevole_nom != username)
  103. ].to_list()
  104. benevole_you_replace = df.benevole_nom[
  105. (df.nom == item.nom) & (df.end == item.start)
  106. ].to_list()
  107. benevole_following_you = df.benevole_nom[
  108. (df.nom == item.nom) & (df.start == item.end)
  109. ].to_list()
  110. creneau_detail = df_creneau[
  111. (df_creneau.nom == item.nom) | (df_creneau.nom == item.description_id)
  112. ]
  113. description = ""
  114. responsable = "undefined"
  115. location = "undefined"
  116. if len(creneau_detail) > 0:
  117. creneau = creneau_detail.iloc[0]
  118. description = creneau.description
  119. responsable = creneau.responsable
  120. location = creneau.lieu
  121. arr.append(
  122. Slot(
  123. name=item.nom,
  124. description=description,
  125. start=item.start,
  126. end=item.end,
  127. location=location,
  128. responsable=responsable,
  129. starting_with_you=getContactList(starting_with_you, df_contact),
  130. benevole_you_replace=getContactList(benevole_you_replace, df_contact),
  131. benevole_following_you=getContactList(
  132. benevole_following_you, df_contact
  133. ),
  134. )
  135. )
  136. return arr
  137. def getCalendarObject(slots: List[Slot]) -> ics.Calendar:
  138. new_calendar = ics.Calendar(creator=PROGRAM_UID)
  139. for slot in slots:
  140. new_calendar.events.add(slot.toIEvent())
  141. return new_calendar
  142. def getCalendarObjects(slots: List[Slot]) -> List[ics.Calendar]:
  143. return [
  144. ics.Calendar(creator=PROGRAM_UID, events=[slot.toIEvent()]) for slot in slots
  145. ]
  146. def getHTMLcontent(slots: List[Slot], name="", render_as_mail=True) -> str:
  147. return JINJA_ENV.get_template("Calendar.html").render(
  148. slots=slots, name=name, render_as_mail=render_as_mail
  149. )
  150. def getHTMLhome(links: List[Tuple[str, str]]) -> str:
  151. return JINJA_ENV.get_template("Home.html").render(links=links)