You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
4.6 KiB

  1. from enum import IntEnum
  2. import datetime
  3. import re
  4. from dateutil import rrule
  5. from .calendar_api import calendar_api
  6. from .utils import to_dateTime, from_dateTime
  7. class weekdays(IntEnum):
  8. SUN = 6
  9. MON = 0
  10. TUE = 1
  11. WED = 2
  12. THU = 3
  13. FRI = 4
  14. SAT = 5
  15. class Calendar:
  16. """Model for representing a Google calendar"""
  17. def __init__(self, api: calendar_api, calendar_id):
  18. self.api = api
  19. if calendar_id in api.ids.keys():
  20. self.name = calendar_id
  21. self.calendar_id = self.api.ids[self.name]
  22. elif calendar_id in api.ids.values():
  23. self.name = self.api.calendars[calendar_id]["summary"]
  24. self.id = calendar_id
  25. else:
  26. raise ValueError("Non-existent calendar specified")
  27. self.calendar_id = calendar_id
  28. def update_or_add_0event(self, event: Event):
  29. event.upload(self.api, self.calendar_id)
  30. def search_events(self, event_name):
  31. pass
  32. def calendar_dict(api: calendar_api):
  33. return dict(
  34. (calendar_name, Calendar(api, calendar_name))
  35. for calendar_name in api.ids.keys()
  36. )
  37. class Event:
  38. """Model for a calendar event that can be uploaded"""
  39. def __init__(
  40. self,
  41. start,
  42. end,
  43. name,
  44. description=None,
  45. recurrence=None,
  46. reminders=None,
  47. attendees=None,
  48. location=None,
  49. id=None,
  50. ):
  51. self.start = start
  52. self.attendees = attendees
  53. self.end = end
  54. self.name = name
  55. self.description = description
  56. self.location = location
  57. self.recurrence = recurrence
  58. self.id = id
  59. if reminders is None:
  60. self.reminders = {"useDefault": True}
  61. else:
  62. self.reminders = reminders
  63. def add_reminder(self, until, method="popup"):
  64. """Add a reminder minutes before an event.
  65. Use either a notification (popup) or email"""
  66. assert method in ("email", "popup")
  67. self.reminders["useDefault"] = False
  68. if isinstance(until, datetime.timedelta):
  69. minutes_until = until.days * 24 * 60
  70. minutes_until += until.seconds // 60
  71. else:
  72. minutes_until = until
  73. self.reminders.setdefault("overrides", []).append(
  74. {"method": method, "minutes": minutes_until}
  75. )
  76. def add_weekly_recurrence(self, until: datetime.datetime, *days):
  77. if not until.tzinfo:
  78. until = until.astimezone()
  79. ret = rrule.rrule(
  80. freq=rrule.WEEKLY,
  81. dtstart=self.start,
  82. wkst=weekdays.SUN,
  83. until=until,
  84. byweekday=days,
  85. )
  86. ret_str = str(ret).split("\n")[-1]
  87. ret_str = re.sub(r"(UNTIL=[^;]+)", r"\1Z", ret_str)
  88. if self.recurrence is None:
  89. self.recurrence = []
  90. self.recurrence.append(ret_str)
  91. def to_json(self):
  92. keys = ("attendees", "description", "location", "recurrence", "reminders")
  93. ret = {
  94. "summary": self.name,
  95. "start": to_dateTime(self.start),
  96. "end": to_dateTime(self.end),
  97. }
  98. for key in keys:
  99. try:
  100. value = self.__getattribute__(key)
  101. if value:
  102. ret[key] = value
  103. except AttributeError:
  104. pass
  105. return ret
  106. def add_attendees(self):
  107. pass
  108. @classmethod
  109. def from_json(cls, body):
  110. args = {}
  111. args["name"] = body.get("summary", "unnamed")
  112. args["start"] = from_dateTime(body["start"])
  113. args["end"] = from_dateTime(body["end"])
  114. keys = ("attendees", "description", "location", "recurrence", "reminders", "id")
  115. for key in keys:
  116. try:
  117. args[key] = body[key]
  118. except KeyError:
  119. pass
  120. instance = cls(**args)
  121. return instance
  122. @classmethod
  123. def from_id(cls, api: calendar_api, calendar_id, event_id):
  124. """creates an event model from specified calendar and event_id"""
  125. event = api.get_event_by_id(calendar_id, event_id)
  126. return cls.from_json(event)
  127. def upload(self, api: calendar_api, calendar_id):
  128. """Upload an event to calendar.
  129. Either modifies an event in place or creates a new event."""
  130. if self.id is not None:
  131. event_id = api.update_event(calendar_id, self.id, self.to_json())
  132. else:
  133. event_id = api.create_event(calendar_id, self.to_json())
  134. self.id = event_id
  135. return event_id
  136. def delete(self, api: calendar_api):
  137. pass