From 264301ecc082c7182b6f327ff777c2056bba696f Mon Sep 17 00:00:00 2001 From: redxef Date: Tue, 14 Nov 2023 18:11:58 +0100 Subject: [PATCH] Fix date generation if no start is specified in the repeat rules. --- adapters/abc.py | 43 +++++++++++++++++++++++++++++++++++++++++++ main.py | 6 ++---- requirements.txt | 1 + 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/adapters/abc.py b/adapters/abc.py index 6607fda..6df7f7f 100644 --- a/adapters/abc.py +++ b/adapters/abc.py @@ -1,8 +1,10 @@ import abc import typing import datetime +import copy import schema +import dateutil.rrule class Adapter(abc.ABC): schema: schema.Schema @@ -30,6 +32,47 @@ class Source(abc.ABC): ) -> typing.Iterable[dict]: raise NotImplementedError() + def get_events_resolved( + self, + start: datetime.datetime | None=None, + until: datetime.timedelta | None=None, + limit=None, + ) -> typing.Iterable[dict]: + until = until if until else datetime.timedelta(days=365) + now = start if start else datetime.datetime.utcnow().astimezone() + now_365 = now + until + for e in self.get_events( + start=start, + until=until, + limit=limit, + ): + if 'recurrence' not in e: + yield e + continue + r = e.pop('recurrence') + r = dateutil.rrule.rrulestr( + '\n'.join(r), + unfold=True, + ignoretz=True, + dtstart=datetime.datetime.fromisoformat( + e['start']['dateTime'] + if 'dateTime' in e['start'] else + e['start']['date'] + ).replace(tzinfo=None) + ) + for t_ in r.between(now.replace(tzinfo=None), now_365.replace(tzinfo=None)): + e_ = copy.deepcopy(e) + if 'dateTime' in e['start']: + e_['start']['dateTime'] = datetime.datetime.combine(t_.date(), datetime.datetime.fromisoformat(e['start']['dateTime']).time()).isoformat() + elif 'date' in e['start']: + e_['start']['date'] = datetime.datetime.combine(t_.date(), datetime.time()) + if 'dateTime' in e['end']: + e_['end']['dateTime'] = datetime.datetime.combine(t_.date(), datetime.datetime.fromisoformat(e['end']['dateTime']).time()).isoformat() + elif 'date' in e['end']: + e_['end']['date'] = datetime.datetime.combine(t_.date(), datetime.time()) + yield e_ + yield e + class Sink(abc.ABC): @abc.abstractmethod diff --git a/main.py b/main.py index 01efb14..dc689f4 100755 --- a/main.py +++ b/main.py @@ -151,7 +151,7 @@ def main(config, dryrun, level, range): source_results = [] for source in sources: try: - events += source.get_events(until=config['range']) + events += source.get_events_resolved(until=config['range']) source_results += [True] except Exception: logger.exception('failed to get events from source %s', source) @@ -167,9 +167,7 @@ def main(config, dryrun, level, range): logger.log(logging.VERBOSE, 'events are: %s', [f"{e.get('summary', '')} ({e.get('start')})" for e in events]) # post events - if dryrun: - logger.info("dryrun; would post events: %s", events) - else: + if not dryrun: sink_results = [] for sink in sinks: try: diff --git a/requirements.txt b/requirements.txt index d1ba0f5..19ae03b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ google-auth-httplib2 google-auth-oauthlib click bs4 +python-dateutil