|
from datetime import time, date, datetime
|
|
from typing import Union
|
|
|
|
from beautiful_date import BeautifulDate, days
|
|
|
|
|
|
class Reminder:
|
|
def __init__(
|
|
self,
|
|
method: str,
|
|
minutes_before_start: int = None,
|
|
days_before: int = None,
|
|
at: time = None
|
|
):
|
|
"""Represents base reminder object
|
|
|
|
Provide `minutes_before_start` to create "relative" reminder.
|
|
Provide `days_before` and `at` to create "absolute" reminder.
|
|
|
|
:param method:
|
|
Method of the reminder. Possible values: email or popup
|
|
:param minutes_before_start:
|
|
Minutes before reminder
|
|
:param days_before:
|
|
Days before reminder
|
|
:param at:
|
|
Specific time for a reminder
|
|
"""
|
|
|
|
if minutes_before_start is None and days_before is None and at is None:
|
|
raise ValueError("Relative reminder needs 'minutes_before_start'. "
|
|
"Absolute reminder 'days_before' and 'at' set. "
|
|
"None of them were provided.")
|
|
|
|
|
|
if minutes_before_start is not None and (days_before is not None or at is not None):
|
|
raise ValueError("Only minutes_before_start or days_before/at can be specified.")
|
|
|
|
|
|
if (days_before is None) != (at is None):
|
|
raise ValueError(f'Both "days_before" and "at" values need to be set '
|
|
f'when using absolute time for a reminder. '
|
|
f'Provided days_before={days_before} and at={at}.')
|
|
|
|
self.method = method
|
|
self.minutes_before_start = minutes_before_start
|
|
self.days_before = days_before
|
|
self.at = at
|
|
|
|
def __eq__(self, other):
|
|
return (
|
|
isinstance(other, Reminder)
|
|
and self.method == other.method
|
|
and self.minutes_before_start == other.minutes_before_start
|
|
and self.days_before == other.days_before
|
|
and self.at == other.at
|
|
)
|
|
|
|
def __str__(self):
|
|
if self.minutes_before_start is not None:
|
|
return '{} - minutes_before_start:{}'.format(self.__class__.__name__, self.minutes_before_start)
|
|
else:
|
|
return '{} - {} days before at {}'.format(self.__class__.__name__, self.days_before, self.at)
|
|
|
|
def __repr__(self):
|
|
return '<{}>'.format(self.__str__())
|
|
|
|
def convert_to_relative(self, start: Union[date, datetime, BeautifulDate]) -> 'Reminder':
|
|
"""Converts absolute reminder (with set `days_before` and `at`) to relative (with set `minutes_before_start`)
|
|
relative to `start` date/datetime. Returns self if `minutes_before_start` already set.
|
|
"""
|
|
if self.minutes_before_start is not None:
|
|
return self
|
|
|
|
tzinfo = start.tzinfo if isinstance(start, datetime) else None
|
|
start_of_the_day = datetime.combine(start, datetime.min.time(), tzinfo=tzinfo)
|
|
|
|
reminder_tzinfo = self.at.tzinfo or tzinfo
|
|
reminder_time = datetime.combine(start_of_the_day - self.days_before * days, self.at, tzinfo=reminder_tzinfo)
|
|
|
|
if isinstance(start, datetime):
|
|
minutes_before_start = int((start - reminder_time).total_seconds() / 60)
|
|
else:
|
|
minutes_before_start = int((start_of_the_day - reminder_time).total_seconds() / 60)
|
|
|
|
return Reminder(
|
|
method=self.method,
|
|
minutes_before_start=minutes_before_start
|
|
)
|
|
|
|
|
|
class EmailReminder(Reminder):
|
|
def __init__(
|
|
self,
|
|
minutes_before_start: int = None,
|
|
days_before: int = None,
|
|
at: time = None
|
|
):
|
|
"""Represents email reminder object
|
|
|
|
Provide `minutes_before_start` to create "relative" reminder.
|
|
Provide `days_before` and `at` to create "absolute" reminder.
|
|
|
|
:param minutes_before_start:
|
|
Minutes before reminder
|
|
:param days_before:
|
|
Days before reminder
|
|
:param at:
|
|
Specific time for a reminder
|
|
"""
|
|
if not days_before and not at and not minutes_before_start:
|
|
minutes_before_start = 60
|
|
super().__init__('email', minutes_before_start, days_before, at)
|
|
|
|
|
|
class PopupReminder(Reminder):
|
|
def __init__(
|
|
self,
|
|
minutes_before_start: int = None,
|
|
days_before: int = None,
|
|
at: time = None
|
|
):
|
|
"""Represents popup reminder object
|
|
|
|
Provide `minutes_before_start` to create "relative" reminder.
|
|
Provide `days_before` and `at` to create "absolute" reminder.
|
|
|
|
:param minutes_before_start:
|
|
Minutes before reminder
|
|
:param days_before:
|
|
Days before reminder
|
|
:param at:
|
|
Specific time for a reminder
|
|
"""
|
|
if not days_before and not at and not minutes_before_start:
|
|
minutes_before_start = 30
|
|
super().__init__('popup', minutes_before_start, days_before, at)
|
|
|