add proxy for the first part and try to develop the second part
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
from ics.alarm.audio import AudioAlarm
|
||||
from ics.alarm.display import DisplayAlarm
|
||||
from ics.alarm.email import EmailAlarm
|
||||
@@ -0,0 +1,44 @@
|
||||
from typing import Optional
|
||||
|
||||
from ics.alarm.base import BaseAlarm
|
||||
|
||||
from ics.grammar.parse import ContentLine
|
||||
from typing import Union
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from ics.serializers.alarm_serializer import AudioAlarmSerializer
|
||||
from ics.parsers.alarm_parser import AudioAlarmParser
|
||||
|
||||
|
||||
class AudioAlarm(BaseAlarm):
|
||||
"""
|
||||
A calendar event VALARM with AUDIO option.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
name = "VALARM"
|
||||
parser = AudioAlarmParser
|
||||
serializer = AudioAlarmSerializer
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
trigger: Union[timedelta, datetime] = None,
|
||||
repeat: int = None,
|
||||
duration: timedelta = None,
|
||||
):
|
||||
|
||||
super().__init__(trigger, repeat, duration)
|
||||
self._sound: Optional[ContentLine] = None
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return "AUDIO"
|
||||
|
||||
@property
|
||||
def sound(self):
|
||||
return self._sound
|
||||
|
||||
@sound.setter
|
||||
def sound(self, sound):
|
||||
assert isinstance(sound, ContentLine)
|
||||
self._sound = sound
|
||||
@@ -0,0 +1,154 @@
|
||||
import copy
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, Union, Any
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
from ics.component import Component
|
||||
from ics.utils import (
|
||||
get_arrow,
|
||||
get_lines
|
||||
)
|
||||
from ics.grammar.parse import Container
|
||||
|
||||
from ics.serializers.alarm_serializer import BaseAlarmSerializer
|
||||
from ics.parsers.alarm_parser import BaseAlarmParser
|
||||
|
||||
|
||||
class BaseAlarm(Component, metaclass=ABCMeta):
|
||||
"""
|
||||
A calendar event VALARM base class
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
name = "VALARM"
|
||||
parser = BaseAlarmParser
|
||||
serializer = BaseAlarmSerializer
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
trigger: Union[timedelta, datetime] = None,
|
||||
repeat: int = None,
|
||||
duration: timedelta = None,
|
||||
) -> None:
|
||||
"""
|
||||
Instantiates a new :class:`ics.alarm.BaseAlarm`.
|
||||
|
||||
Adheres to RFC5545 VALARM standard: http://icalendar.org/iCalendar-RFC-5545/3-6-6-alarm-component.html
|
||||
|
||||
Args:
|
||||
trigger (datetime.timedelta OR datetime.datetime) : Timespan to alert before parent action, or absolute time to alert
|
||||
repeat (integer) : How many times to repeat the alarm
|
||||
duration (datetime.timedelta) : Duration between repeats
|
||||
|
||||
Raises:
|
||||
ValueError: If trigger, repeat, or duration do not match the RFC spec.
|
||||
"""
|
||||
# Set initial values
|
||||
self._trigger: Optional[Union[timedelta, datetime]] = None
|
||||
self._repeat: Optional[int] = None
|
||||
self._duration: Optional[timedelta] = None
|
||||
|
||||
# Validate and parse
|
||||
self.trigger = trigger
|
||||
|
||||
# XOR repeat and duration
|
||||
if (repeat is not None) and (duration is None):
|
||||
raise ValueError(
|
||||
"A definition of an alarm with a repeating trigger MUST include both the DURATION and REPEAT properties."
|
||||
)
|
||||
|
||||
if repeat:
|
||||
self.repeat = repeat
|
||||
|
||||
if duration:
|
||||
self.duration = duration
|
||||
|
||||
self.extra = Container(name="VALARM")
|
||||
|
||||
@classmethod
|
||||
def _from_container(cls, container: Container, *args: Any, **kwargs: Any):
|
||||
ret = super()._from_container(container, *args, **kwargs)
|
||||
get_lines(ret.extra, "ACTION", keep=False) # Just drop the ACTION line
|
||||
return ret
|
||||
|
||||
@property
|
||||
def trigger(self) -> Optional[Union[timedelta, datetime]]:
|
||||
"""The trigger condition for the alarm
|
||||
|
||||
| Returns either a timedelta or datetime object
|
||||
"""
|
||||
return self._trigger
|
||||
|
||||
@trigger.setter
|
||||
def trigger(self, value: Optional[Union[timedelta, datetime]]) -> None:
|
||||
if isinstance(value, datetime):
|
||||
value = get_arrow(value)
|
||||
|
||||
self._trigger = value
|
||||
|
||||
@property
|
||||
def repeat(self) -> Optional[int]:
|
||||
"""Number of times to repeat alarm
|
||||
|
||||
| Returns an integer for number of alarm repeats
|
||||
| Value must be >= 0
|
||||
"""
|
||||
return self._repeat
|
||||
|
||||
@repeat.setter
|
||||
def repeat(self, value: Optional[int]) -> None:
|
||||
if value is not None and value < 0:
|
||||
raise ValueError("Repeat must be great than or equal to 0.")
|
||||
|
||||
self._repeat = value
|
||||
|
||||
@property
|
||||
def duration(self) -> Optional[timedelta]:
|
||||
"""Duration between alarm repeats
|
||||
|
||||
| Returns a timedelta object
|
||||
| Timespan must return positive total_seconds() value
|
||||
"""
|
||||
return self._duration
|
||||
|
||||
@duration.setter
|
||||
def duration(self, value: Optional[timedelta]) -> None:
|
||||
if value is not None and value.total_seconds() < 0:
|
||||
raise ValueError("Alarm duration timespan must be positive.")
|
||||
|
||||
self._duration = value
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def action(self):
|
||||
""" VALARM action to be implemented by concrete classes
|
||||
"""
|
||||
raise NotImplementedError("Base class cannot be instantiated directly")
|
||||
|
||||
def __repr__(self):
|
||||
value = "{0} trigger:{1}".format(type(self).__name__, self.trigger)
|
||||
if self.repeat:
|
||||
value += " repeat:{0} duration:{1}".format(self.repeat, self.duration)
|
||||
|
||||
return "<{0}>".format(value)
|
||||
|
||||
def __ne__(self, other) -> bool:
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
"""Two alarms are considered equal if they have the same type and base values."""
|
||||
|
||||
return (
|
||||
type(self) is type(other)
|
||||
and self.trigger == other.trigger
|
||||
and self.repeat == other.repeat
|
||||
and self.duration == other.duration
|
||||
)
|
||||
|
||||
def clone(self):
|
||||
"""
|
||||
Returns:
|
||||
Alarm: an exact copy of self"""
|
||||
clone = copy.copy(self)
|
||||
clone.extra = clone.extra.clone()
|
||||
return clone
|
||||
@@ -0,0 +1,33 @@
|
||||
from ics.alarm.base import BaseAlarm
|
||||
import copy
|
||||
from typing import Union
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from ics.serializers.alarm_serializer import CustomAlarmSerializer
|
||||
from ics.parsers.alarm_parser import CustomAlarmParser
|
||||
|
||||
|
||||
class CustomAlarm(BaseAlarm):
|
||||
"""
|
||||
A calendar event VALARM with custom ACTION.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
name = "VALARM"
|
||||
parser = CustomAlarmParser
|
||||
serializer = CustomAlarmSerializer
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
trigger: Union[timedelta, datetime] = None,
|
||||
repeat: int = None,
|
||||
duration: timedelta = None,
|
||||
action: str = None,
|
||||
) -> None:
|
||||
super().__init__(trigger, repeat, duration)
|
||||
|
||||
self._action = action
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return self._action
|
||||
@@ -0,0 +1,34 @@
|
||||
from ics.alarm.base import BaseAlarm
|
||||
from typing import Union
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
from ics.serializers.alarm_serializer import DisplayAlarmSerializer
|
||||
from ics.parsers.alarm_parser import DisplayAlarmParser
|
||||
|
||||
|
||||
class DisplayAlarm(BaseAlarm):
|
||||
"""
|
||||
A calendar event VALARM with DISPLAY option.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
name = "VALARM"
|
||||
parser = DisplayAlarmParser
|
||||
serializer = DisplayAlarmSerializer
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
trigger: Union[timedelta, datetime] = None,
|
||||
repeat: int = None,
|
||||
duration: timedelta = None,
|
||||
display_text: str = None,
|
||||
):
|
||||
|
||||
super().__init__(trigger, repeat, duration)
|
||||
|
||||
self.display_text = display_text
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return "DISPLAY"
|
||||
@@ -0,0 +1,38 @@
|
||||
from ics.attendee import Attendee
|
||||
from ics.alarm.base import BaseAlarm
|
||||
from typing import Union, List
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from ics.serializers.alarm_serializer import EmailAlarmSerializer
|
||||
from ics.parsers.alarm_parser import EmailAlarmParser
|
||||
|
||||
|
||||
class EmailAlarm(BaseAlarm):
|
||||
"""
|
||||
A calendar event VALARM with Email option.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
name = "VALARM"
|
||||
parser = EmailAlarmParser
|
||||
serializer = EmailAlarmSerializer
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
trigger: Union[timedelta, datetime] = None,
|
||||
repeat: int = None,
|
||||
duration: timedelta = None,
|
||||
subject: str = None,
|
||||
body: str = None,
|
||||
recipients: List[Attendee] = None,
|
||||
):
|
||||
|
||||
super().__init__(trigger, repeat, duration)
|
||||
|
||||
self.subject = subject
|
||||
self.body = body
|
||||
self.recipients = recipients if recipients else []
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return "EMAIL"
|
||||
@@ -0,0 +1,19 @@
|
||||
from ics.alarm.base import BaseAlarm
|
||||
|
||||
from ics.serializers.alarm_serializer import NoneAlarmSerializer
|
||||
from ics.parsers.alarm_parser import NoneAlarmParser
|
||||
|
||||
|
||||
class NoneAlarm(BaseAlarm):
|
||||
"""
|
||||
A calendar event VALARM with NONE option.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
name = "VALARM"
|
||||
parser = NoneAlarmParser
|
||||
serializer = NoneAlarmSerializer
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
return "NONE"
|
||||
@@ -0,0 +1,28 @@
|
||||
from ics.alarm.audio import AudioAlarm
|
||||
from ics.alarm.none import NoneAlarm
|
||||
from ics.alarm.custom import CustomAlarm
|
||||
from ics.alarm.display import DisplayAlarm
|
||||
from ics.alarm.email import EmailAlarm
|
||||
from ics.utils import get_lines
|
||||
|
||||
|
||||
def get_type_from_action(action_type):
|
||||
if action_type == "DISPLAY":
|
||||
return DisplayAlarm
|
||||
elif action_type == "AUDIO":
|
||||
return AudioAlarm
|
||||
elif action_type == "NONE":
|
||||
return NoneAlarm
|
||||
elif action_type == 'EMAIL':
|
||||
return EmailAlarm
|
||||
else:
|
||||
return CustomAlarm
|
||||
|
||||
|
||||
def get_type_from_container(container):
|
||||
action_type_lines = get_lines(container, "ACTION", keep=True)
|
||||
if len(action_type_lines) > 1:
|
||||
raise ValueError("Too many ACTION parameters in VALARM")
|
||||
|
||||
action_type = action_type_lines[0]
|
||||
return get_type_from_action(action_type.value)
|
||||
Reference in New Issue
Block a user