File size: 5,342 Bytes
550665c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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

        """
        # Nothing was provided
        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.")

        # Both minutes_before_start and days_before/at 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.")

        # Only one of days_before and at was provided
        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)