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.

136 lines
3.8 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. pass
  18. class Event:
  19. """Model for a calendar event that can be uploaded"""
  20. def __init__(
  21. self,
  22. start,
  23. end,
  24. name,
  25. description=None,
  26. recurrence=None,
  27. reminders=None,
  28. attendees=None,
  29. location=None,
  30. id=None,
  31. ):
  32. self.start = start
  33. self.attendees = attendees
  34. self.end = end
  35. self.name = name
  36. self.description = description
  37. self.location = location
  38. self.recurrence = recurrence
  39. self.id = id
  40. if reminders is None:
  41. self.reminders = {"useDefault": True}
  42. else:
  43. self.reminders = reminders
  44. def add_reminder(self, until, method="popup"):
  45. """Add a reminder minutes before an event.
  46. Use either a notification (popup) or email"""
  47. assert method in ("email", "popup")
  48. self.reminders["useDefault"] = False
  49. if isinstance(until, datetime.timedelta):
  50. minutes_until = until.days * 24 * 60
  51. minutes_until += until.seconds // 60
  52. else:
  53. minutes_until = until
  54. self.reminders.setdefault("overrides", []).append(
  55. {"method": method, "minutes": minutes_until}
  56. )
  57. def add_weekly_recurrence(self, until: datetime.datetime, *days):
  58. if not until.tzinfo:
  59. until = until.astimezone()
  60. ret = rrule.rrule(
  61. freq=rrule.WEEKLY,
  62. dtstart=self.start,
  63. wkst=weekdays.SUN,
  64. until=until,
  65. byweekday=days,
  66. )
  67. ret_str = str(ret).split("\n")[-1]
  68. ret_str = re.sub(r"(UNTIL=[^;]+)", r"\1Z", ret_str)
  69. if self.recurrence is None:
  70. self.recurrence = []
  71. self.recurrence.append(ret_str)
  72. def to_json(self):
  73. keys = ("attendees", "description", "location", "recurrence", "reminders")
  74. ret = {
  75. "summary": self.name,
  76. "start": to_dateTime(self.start),
  77. "end": to_dateTime(self.end),
  78. }
  79. for key in keys:
  80. try:
  81. value = self.__getattribute__(key)
  82. if value:
  83. ret[key] = value
  84. except AttributeError:
  85. pass
  86. return ret
  87. def add_attendees(self):
  88. pass
  89. @classmethod
  90. def from_json(cls, body):
  91. args = {}
  92. args["name"] = body.get("summary", "unnamed")
  93. args["start"] = from_dateTime(body["start"])
  94. args["end"] = from_dateTime(body["end"])
  95. keys = ("attendees", "description", "location", "recurrence", "reminders", "id")
  96. for key in keys:
  97. try:
  98. args[key] = body[key]
  99. except KeyError:
  100. pass
  101. instance = cls(**args)
  102. return instance
  103. @classmethod
  104. def from_id(cls, api: calendar_api, calendar_id, event_id):
  105. """creates an event model from specified calendar and event_id"""
  106. event = api.get_event_by_id(calendar_id, event_id)
  107. return cls.from_json(event)
  108. def upload(self, api: calendar_api, calendar_id):
  109. """Upload an event to calendar.
  110. Either modifies an event in place or creates a new event."""
  111. if self.id is not None:
  112. event_id = api.update_event(calendar_id, self.id, self.to_json())
  113. else:
  114. event_id = api.create_event(calendar_id, self.to_json())
  115. self.id = event_id
  116. return event_id
  117. def delete(self, api: calendar_api):
  118. pass