Пример #1
0
    def parse_event(self, event, extra):
        try:
            uid = str(event['guid'])

            # The entirety of the raw event data in json representation.
            raw_data = str(event)

            subject = event.get('title', '')[:SUBJECT_MAX_LEN]
            body = event.get('description', None)
            location = event.get('location', None)
            if location:
                location = location[:LOCATION_MAX_LEN]
            all_day = event.get('allDay', False)
            read_only = event.get('readOnly')

            # for some reason iCloud gives the date as YYYYMMDD for the first
            # entry and then the Y, M, D, H, S as later entries.
            start_date = event['startDate'][1:]
            end_date = event['endDate'][1:]

            start = datetime.datetime(*start_date[:-1])
            end = datetime.datetime(*end_date[:-1])

            recurrence = event['recurrence']

            # iCloud doesn't give us busy information
            busy = True

            # reminder format is super-funky, punt for now -cg3
            reminders = str([])

            # and for some reason iCloud isn't giving us participants
            participants = []

        except (KeyError, AttributeError):
            raise MalformedEventError()

        return Event(account_id=self.account_id,
                     uid=uid,
                     provider_name=self.PROVIDER_NAME,
                     raw_data=raw_data,
                     subject=subject,
                     body=body,
                     location=location,
                     reminders=reminders,
                     recurrence=recurrence,
                     start=start,
                     end=end,
                     busy=busy,
                     all_day=all_day,
                     read_only=read_only,
                     source='remote',
                     is_owner=True,
                     participants=participants)
Пример #2
0
    def parse_event(self, event, cal_info):
        """Constructs an Event object from a Google calendar entry.

        Parameters
        ----------
        event: gdata.calendar.entry.CalendarEntry
            The Google calendar entry to parse.

        Returns
        -------
        ..models.tables.base.Event
            A corresponding Inbox Event instance.

        Raises
        ------
        MalformedEventError
           If the calendar data could not be parsed correctly.
        """
        try:
            uid = str(event['id'])

            # The entirety of the raw event data in json representation.
            raw_data = str(event)

            # 'cancelled' events signify those instances within a series
            # that have been cancelled (for that given series). As such,
            # since full support for dealing with single instances within
            # a reocurring event series is not added, right now we just
            # treat this event as 'malformed'. -cg3
            # TODO: Add support for reocurring events (see ways to handle
            # this generically across providers)
            if 'status' in event and event['status'] == 'cancelled':
                raise MalformedEventError()

            subject = event.get('summary', '')[:SUBJECT_MAX_LEN]
            body = event.get('description', None)
            location = event.get('location', None)
            if location:
                location = location[:LOCATION_MAX_LEN]
            all_day = False
            read_only = True
            is_owner = False

            start = event['start']
            end = event['end']
            g_reccur = event.get('recurrence', None)
            recurrence = str(g_reccur) if g_reccur else None

            busy = event.get('transparency', True)
            if busy == 'transparent':
                busy = False

            reminders = []
            if 'dateTime' in start:
                if event['reminders']['useDefault']:
                    reminder_source = cal_info['defaultReminders']
                elif 'overrides' in event['reminders']:
                    reminder_source = event['reminders']['overrides']
                else:
                    reminder_source = None

                if reminder_source:
                    for reminder in reminder_source:
                        reminders.append(reminder['minutes'])

                start = parse_datetime(start['dateTime'])
                end = parse_datetime(end['dateTime'])
            else:
                start = date_parser.parse(start['date'])
                end = date_parser.parse(end['date'])
                all_day = True

            reminders = str(reminders)

            # Convert google's notion of status into our own
            participants = []
            status_map = {'accepted': 'yes', 'needsAction': 'noreply',
                          'declined': 'no', 'tentative': 'maybe'}
            for attendee in event.get('attendees', []):
                g_status = attendee.get('responseStatus')
                if g_status not in status_map:
                    raise MalformedEventError()
                status = status_map[g_status]

                email = attendee.get('email')
                if not email:
                    raise MalformedEventError()

                name = attendee.get('displayName')

                notes = None
                if 'additionalGuests' in attendee:
                    notes = "Guests: {}".format(attendee['additionalGuests'])
                    if 'comment' in attendee:
                        notes += " Notes: {}".format(attendee['comment'])
                elif 'comment' in attendee:
                    notes = "Notes: {}".format(attendee['comment'])

                participants.append(Participant(email_address=email,
                                                name=name,
                                                status=status,
                                                notes=notes))

            if 'self' in event['creator']:
                is_owner = True
                read_only = False
            elif 'guestsCanModify' in event:
                read_only = False

            owner = "{} <{}>".format(event['creator']['displayName'],
                                     event['creator']['email'])

        except (KeyError, AttributeError):
            raise MalformedEventError()

        return Event(account_id=self.account_id,
                     uid=uid,
                     provider_name=self.PROVIDER_NAME,
                     raw_data=raw_data,
                     subject=subject,
                     body=body,
                     location=location,
                     reminders=reminders,
                     recurrence=recurrence,
                     start=start,
                     end=end,
                     owner=owner,
                     is_owner=is_owner,
                     busy=busy,
                     all_day=all_day,
                     read_only=read_only,
                     source='remote',
                     participants=participants)
Пример #3
0
def events_from_ics(namespace, calendar, ics_str):
    try:
        cal = iCalendar.from_ical(ics_str)
    except (ValueError, IndexError, KeyError):
        raise MalformedEventError()

    events = []

    # See: https://tools.ietf.org/html/rfc5546#section-3.2
    calendar_method = None

    for component in cal.walk():
        if component.name == "VCALENDAR":
            calendar_method = component.get('method')

        if component.name == "VTIMEZONE":
            tzname = component.get('TZID')
            assert tzname in timezones_table,\
                "Non-UTC timezone should be in table"

        if component.name == "VEVENT":
            # Make sure the times are in UTC.
            try:
                original_start = component.get('dtstart').dt
                original_end = component.get('dtend').dt
            except AttributeError:
                raise MalformedEventError("Event lacks start and/or end time")

            start = original_start
            end = original_end
            original_start_tz = None

            if isinstance(start, datetime) and isinstance(end, datetime):
                all_day = False
                original_start_tz = str(original_start.tzinfo)

                # icalendar doesn't parse Windows timezones yet
                # (see: https://github.com/collective/icalendar/issues/44)
                # so we look if the timezone isn't in our Windows-TZ
                # to Olson-TZ table.
                if original_start.tzinfo is None:
                    tzid = component.get('dtstart').params.get('TZID', None)
                    assert tzid in timezones_table,\
                        "Non-UTC timezone should be in table"

                    corresponding_tz = timezones_table[tzid]
                    original_start_tz = corresponding_tz

                    local_timezone = pytz.timezone(corresponding_tz)
                    start = local_timezone.localize(original_start)

                if original_end.tzinfo is None:
                    tzid = component.get('dtend').params.get('TZID', None)
                    assert tzid in timezones_table,\
                        "Non-UTC timezone should be in table"

                    corresponding_tz = timezones_table[tzid]
                    local_timezone = pytz.timezone(corresponding_tz)
                    end = local_timezone.localize(original_end)

            elif isinstance(start, date) and isinstance(end, date):
                all_day = True
                start = arrow.get(start)
                end = arrow.get(end)

            # Get the last modification date.
            # Exchange uses DtStamp, iCloud and Gmail LAST-MODIFIED.
            last_modified_tstamp = component.get('dtstamp')
            last_modified = None
            if last_modified_tstamp is not None:
                # This is one surprising instance of Exchange doing
                # the right thing by giving us an UTC timestamp. Also note that
                # Google calendar also include the DtStamp field, probably to
                # be a good citizen.
                if last_modified_tstamp.dt.tzinfo is not None:
                    last_modified = last_modified_tstamp.dt
                else:
                    raise NotImplementedError("We don't support arcane Windows"
                                              " timezones in timestamps yet")
            else:
                # Try to look for a LAST-MODIFIED element instead.
                # Note: LAST-MODIFIED is always in UTC.
                # http://www.kanzaki.com/docs/ical/lastModified.html
                last_modified = component.get('last-modified').dt
                assert last_modified is not None, \
                    "Event should have a DtStamp or LAST-MODIFIED timestamp"

            title = None
            summaries = component.get('summary', [])
            if not isinstance(summaries, list):
                summaries = [summaries]

            if summaries != []:
                title = " - ".join(summaries)

            description = unicode(component.get('description'))

            event_status = component.get('status')
            if event_status is not None:
                event_status = event_status.lower()
            else:
                # Some providers (e.g: iCloud) don't use the status field.
                # Instead they use the METHOD field to signal cancellations.
                method = component.get('method')
                if method and method.lower() == 'cancel':
                    event_status = 'cancelled'
                elif calendar_method and calendar_method.lower() == 'cancel':
                    # So, this particular event was not cancelled. Maybe the
                    # whole calendar was.
                    event_status = 'cancelled'
                else:
                    # Otherwise assume the event has been confirmed.
                    event_status = 'confirmed'

            assert event_status in EVENT_STATUSES

            recur = component.get('rrule')
            if recur:
                recur = "RRULE:{}".format(recur.to_ical())

            participants = []

            organizer = component.get('organizer')
            if organizer:
                # Here's the problem. Gmail and Exchange define the organizer
                # field like this:
                #
                # ORGANIZER;CN="User";EMAIL="*****@*****.**":mailto:[email protected]
                # but iCloud does it like this:
                # ORGANIZER;CN=User;[email protected]:mailto:
                # [email protected]
                # so what we first try to get the EMAIL field, and only if
                # it's not present we use the MAILTO: link.
                if 'EMAIL' in organizer.params:
                    organizer = organizer.params['EMAIL']
                else:
                    organizer = unicode(organizer)
                    if organizer.startswith('mailto:'):
                        organizer = organizer[7:]

            if (namespace.account.email_address == canonicalize_address(
                    organizer)):
                is_owner = True
            else:
                is_owner = False

            attendees = component.get('attendee', [])

            # the iCalendar python module doesn't return a list when
            # there's only one attendee. Go figure.
            if not isinstance(attendees, list):
                attendees = [attendees]

            for attendee in attendees:
                email = unicode(attendee)
                # strip mailto: if it exists
                if email.lower().startswith('mailto:'):
                    email = email[7:]
                try:
                    name = attendee.params['CN']
                except KeyError:
                    name = None

                status_map = {
                    'NEEDS-ACTION': 'noreply',
                    'ACCEPTED': 'yes',
                    'DECLINED': 'no',
                    'TENTATIVE': 'maybe'
                }
                status = 'noreply'
                try:
                    a_status = attendee.params['PARTSTAT']
                    status = status_map[a_status]
                except KeyError:
                    pass

                notes = None
                try:
                    guests = attendee.params['X-NUM-GUESTS']
                    notes = "Guests: {}".format(guests)
                except KeyError:
                    pass

                participants.append({
                    'email': email,
                    'name': name,
                    'status': status,
                    'notes': notes,
                    'guests': []
                })

            location = component.get('location')
            uid = str(component.get('uid'))

            event = Event(namespace=namespace,
                          calendar=calendar,
                          uid=uid,
                          provider_name='ics',
                          raw_data=component.to_ical(),
                          title=title,
                          description=description,
                          location=location,
                          reminders=str([]),
                          recurrence=recur,
                          start=start,
                          end=end,
                          busy=True,
                          all_day=all_day,
                          read_only=True,
                          is_owner=is_owner,
                          last_modified=last_modified,
                          original_start_tz=original_start_tz,
                          source='local',
                          status=event_status,
                          participants=participants)

            events.append(event)
    return events
Пример #4
0
def events_from_ics(namespace, calendar, ics_str):
    try:
        cal = iCalendar.from_ical(ics_str)
    except (ValueError, IndexError, KeyError):
        raise MalformedEventError()

    events = dict(invites=[], rsvps=[])

    # See: https://tools.ietf.org/html/rfc5546#section-3.2
    calendar_method = None

    for component in cal.walk():
        if component.name == "VCALENDAR":
            calendar_method = component.get("method")

        if component.name == "VTIMEZONE":
            tzname = component.get("TZID")
            assert tzname in timezones_table, "Non-UTC timezone should be in table"

        if component.name == "VEVENT":
            # Make sure the times are in UTC.
            try:
                original_start = component.get("dtstart").dt
                original_end = component.get("dtend").dt
            except AttributeError:
                raise MalformedEventError("Event lacks start and/or end time")

            start = original_start
            end = original_end
            original_start_tz = None

            all_day = False
            if isinstance(start, datetime) and isinstance(end, datetime):
                tzid = str(original_start.tzinfo)
                if tzid in timezones_table:
                    original_start_tz = timezones_table[tzid]

                if original_start.tzinfo is None:
                    tzid = component.get("dtstart").params.get("TZID", None)
                    assert (tzid in timezones_table
                            ), "Non-UTC timezone should be in table"

                    corresponding_tz = timezones_table[tzid]
                    original_start_tz = corresponding_tz

                    local_timezone = pytz.timezone(corresponding_tz)
                    original_start = local_timezone.localize(original_start)

                if original_end.tzinfo is None:
                    tzid = component.get("dtend").params.get("TZID", None)
                    assert (tzid in timezones_table
                            ), "Non-UTC timezone should be in table"

                    corresponding_tz = timezones_table[tzid]
                    local_timezone = pytz.timezone(corresponding_tz)
                    original_end = local_timezone.localize(original_end)

                # Now that we have tz-aware datetimes, convert them to UTC
                start = original_start.astimezone(pytz.UTC)
                end = original_end.astimezone(pytz.UTC)

            elif isinstance(start, date) and isinstance(end, date):
                all_day = True
                start = arrow.get(start)
                end = arrow.get(end)

            assert isinstance(start, type(end)), ("Start and end should be of "
                                                  "the same type")

            # Get the last modification date.
            # Exchange uses DtStamp, iCloud and Gmail LAST-MODIFIED.
            component_dtstamp = component.get("dtstamp")
            component_last_modified = component.get("last-modified")
            last_modified = None

            if component_dtstamp is not None:
                # This is one surprising instance of Exchange doing
                # the right thing by giving us an UTC timestamp. Also note that
                # Google calendar also include the DtStamp field, probably to
                # be a good citizen.
                if component_dtstamp.dt.tzinfo is not None:
                    last_modified = component_dtstamp.dt
                else:
                    raise NotImplementedError("We don't support arcane Windows"
                                              " timezones in timestamps yet")
            elif component_last_modified is not None:
                # Try to look for a LAST-MODIFIED element instead.
                # Note: LAST-MODIFIED is always in UTC.
                # http://www.kanzaki.com/docs/ical/lastModified.html
                last_modified = component_last_modified.dt

            title = None
            summaries = component.get("summary", [])
            if not isinstance(summaries, list):
                summaries = [summaries]

            if summaries != []:
                title = " - ".join(summaries)

            description = component.get("description")
            if description is not None:
                description = unicode(description)

            event_status = component.get("status")
            if event_status is not None:
                event_status = event_status.lower()
            else:
                # Some providers (e.g: iCloud) don't use the status field.
                # Instead they use the METHOD field to signal cancellations.
                method = component.get("method")
                if method and method.lower() == "cancel":
                    event_status = "cancelled"
                elif calendar_method and calendar_method.lower() == "cancel":
                    # So, this particular event was not cancelled. Maybe the
                    # whole calendar was.
                    event_status = "cancelled"
                else:
                    # Otherwise assume the event has been confirmed.
                    event_status = "confirmed"

            assert event_status in EVENT_STATUSES

            recur = component.get("rrule")
            if recur:
                recur = "RRULE:{}".format(recur.to_ical())

            participants = []

            organizer = component.get("organizer")
            organizer_name = None
            organizer_email = None
            if organizer:
                organizer_email = unicode(organizer)
                if organizer_email.lower().startswith("mailto:"):
                    organizer_email = organizer_email[7:]

                if "CN" in organizer.params:
                    organizer_name = organizer.params["CN"]

                owner = formataddr([organizer_name, organizer_email.lower()])
            else:
                owner = None

            is_owner = False
            if owner is not None and (
                    namespace.account.email_address
                    == canonicalize_address(organizer_email)):
                is_owner = True

            attendees = component.get("attendee", [])

            # the iCalendar python module doesn't return a list when
            # there's only one attendee. Go figure.
            if not isinstance(attendees, list):
                attendees = [attendees]

            for attendee in attendees:
                email = unicode(attendee)
                # strip mailto: if it exists
                if email.lower().startswith("mailto:"):
                    email = email[7:]
                try:
                    name = attendee.params["CN"]
                except KeyError:
                    name = None

                status_map = {
                    "NEEDS-ACTION": "noreply",
                    "ACCEPTED": "yes",
                    "DECLINED": "no",
                    "TENTATIVE": "maybe",
                }
                status = "noreply"
                try:
                    a_status = attendee.params["PARTSTAT"]
                    status = status_map[a_status]
                except KeyError:
                    pass

                notes = None
                try:
                    guests = attendee.params["X-NUM-GUESTS"]
                    notes = u"Guests: {}".format(guests)
                except KeyError:
                    pass

                participants.append({
                    "email": email.lower(),
                    "name": name,
                    "status": status,
                    "notes": notes,
                    "guests": [],
                })

            location = component.get("location")
            uid = str(component.get("uid"))
            sequence_number = int(component.get("sequence", 0))

            # Some services (I'm looking at you, http://www.foogi.me/)
            # don't follow the spec and generate icalendar files with
            # ridiculously big sequence numbers. Truncate them to fit in
            # our db.
            if sequence_number > 2147483647:
                sequence_number = 2147483647

            event = Event(
                namespace=namespace,
                calendar=calendar,
                uid=uid,
                provider_name="ics",
                raw_data=component.to_ical(),
                title=title,
                description=description,
                location=location,
                reminders=str([]),
                recurrence=recur,
                start=start,
                end=end,
                busy=True,
                all_day=all_day,
                read_only=True,
                owner=owner,
                is_owner=is_owner,
                last_modified=last_modified,
                original_start_tz=original_start_tz,
                source="local",
                status=event_status,
                sequence_number=sequence_number,
                participants=participants,
            )

            # We need to distinguish between invites/updates/cancellations
            # and RSVPs.
            if calendar_method == "REQUEST" or calendar_method == "CANCEL":
                events["invites"].append(event)
            elif calendar_method == "REPLY":
                events["rsvps"].append(event)

    return events
Пример #5
0
Файл: ical.py Проект: wmv/inbox
def events_from_ics(namespace, calendar, ics_str):
    try:
        cal = Calendar.from_ical(ics_str)
    except ValueError:
        raise MalformedEventError()

    events = []
    for component in cal.walk():
        if component.name == "VEVENT":
            start = component.get('dtstart').dt
            end = component.get('dtend').dt
            title = component.get('summary')
            description = str(component.get('description'))
            if isinstance(start, datetime):
                all_day = False
            else:
                all_day = True
                start = datetime.combine(start, datetime.min.time())
                end = datetime.combine(end, datetime.min.time())

            reccur = component.get('rrule')
            if reccur:
                reccur = reccur.to_ical()
            else:
                reccur = ''
            participants = []
            for attendee in component.get('attendee'):
                email = str(attendee)
                # strip mailto: if it exists
                if email.startswith('mailto:'):
                    email = email[7:]
                try:
                    name = attendee.params['CN']
                except KeyError:
                    name = None

                status_map = {
                    'NEEDS-ACTION': 'noreply',
                    'ACCEPTED': 'yes',
                    'DECLINED': 'no',
                    'TENTATIVE': 'maybe'
                }
                status = 'noreply'
                try:
                    a_status = attendee.params['PARTSTAT']
                    status = status_map[a_status]
                except KeyError:
                    pass

                notes = None
                try:
                    guests = attendee.params['X-NUM-GUESTS']
                    notes = "Guests: {}".format(guests)
                except KeyError:
                    pass

                participant = Participant(email_address=email,
                                          status=status,
                                          name=name,
                                          notes=notes)

                participants.append(participant)
            location = component.get('location')
            organizer = component.get('organizer')
            if (organizer):
                organizer = str(organizer)
                if organizer.startswith('mailto:'):
                    organizer = organizer[7:]

            uid = str(component.get('uid'))
            event = Event(namespace=namespace,
                          calendar=calendar,
                          uid=uid,
                          provider_name='ics',
                          raw_data=component.to_ical(),
                          title=title,
                          description=description,
                          location=location,
                          reminders=str([]),
                          recurrence=reccur,
                          start=start,
                          end=end,
                          busy=True,
                          all_day=all_day,
                          read_only=True,
                          source='local')

            event.participants = participants
            events.append(event)
    return events
Пример #6
0
    def parse_event(self, event, cal_info):
        """Constructs an Event object from a Google calendar entry.

        Parameters
        ----------
        event: gdata.calendar.entry.CalendarEntry
            The Google calendar entry to parse.

        Returns
        -------
        ..models.tables.base.Event
            A corresponding Inbox Event instance.

        Raises
        ------
        MalformedEventError
           If the calendar data could not be parsed correctly.
        """
        try:
            uid = str(event['id'])

            # The entirety of the raw event data in json representation.
            raw_data = str(event)

            # 'cancelled' events signify those instances within a series
            # that have been cancelled (for that given series). As such,
            # since full support for dealing with single instances within
            # a reocurring event series is not added, right now we just
            # ignore the event. -cg3
            # TODO: Add support for reocurring events (see ways to handle
            # this generically across providers)
            if 'status' in event and event['status'] == 'cancelled':
                return None

            title = event.get('summary', '')
            description = event.get('description', None)
            location = event.get('location', None)
            all_day = False
            read_only = True
            is_owner = False

            start = event['start']
            end = event['end']
            g_recur = event.get('recurrence', None)

            recurrence = str(g_recur) if g_recur else None

            busy = event.get('transparency', True)
            if busy == 'transparent':
                busy = False

            reminders = []
            if 'dateTime' in start:
                if event['reminders']['useDefault']:
                    reminder_source = cal_info['defaultReminders']
                elif 'overrides' in event['reminders']:
                    reminder_source = event['reminders']['overrides']
                else:
                    reminder_source = None

                if reminder_source:
                    for reminder in reminder_source:
                        reminders.append(reminder['minutes'])

                try:
                    start = parse_datetime(start['dateTime'])
                    end = parse_datetime(end['dateTime'])
                except TypeError:
                    self.log.error('Invalid start: {} or end: {}'.format(
                        start['dateTime'], end['dateTime']))
                    raise MalformedEventError()

            else:
                start = date_parser.parse(start['date'])
                end = date_parser.parse(end['date'])
                all_day = True

            reminders = str(reminders)

            # Convert google's notion of status into our own
            participants = []
            for attendee in event.get('attendees', []):
                g_status = attendee.get('responseStatus')
                if g_status not in GoogleEventsProvider.status_map:
                    raise MalformedEventError()
                status = GoogleEventsProvider.status_map[g_status]

                email = attendee.get('email')
                if not email:
                    raise MalformedEventError()

                name = attendee.get('displayName')

                notes = None
                guests = 0
                if 'additionalGuests' in attendee:
                    guests = attendee['additionalGuests']
                elif 'comment' in attendee:
                    notes = attendee['comment']

                participants.append({
                    'email_address': email,
                    'name': name,
                    'status': status,
                    'notes': notes,
                    'guests': guests
                })

            if 'guestsCanModify' in event:
                read_only = False
            owner = ''
            if 'creator' in event:
                creator = event['creator']
                if 'self' in creator:
                    is_owner = True
                    read_only = False

                owner = u'{} <{}>'.format(creator.get('displayName', ''),
                                          creator.get('email', ''))

        except (KeyError, AttributeError):
            raise MalformedEventError()

        return Event(namespace_id=self.namespace_id,
                     uid=uid,
                     provider_name=self.PROVIDER_NAME,
                     raw_data=raw_data,
                     title=title,
                     description=description,
                     location=location,
                     reminders=reminders,
                     recurrence=recurrence,
                     start=start,
                     end=end,
                     owner=owner,
                     is_owner=is_owner,
                     busy=busy,
                     all_day=all_day,
                     read_only=read_only,
                     source='remote',
                     participants=participants)
Пример #7
0
    def parse_event(self, event, extra):
        user_id = extra['user_id']
        stored_uids = extra['stored_uids']
        try:
            uid = str(event['id'])

            if uid in stored_uids:
                raise MalformedEventError()

            # The entirety of the raw event data in json representation.
            raw_data = str(event)

            title = event.get('name', '')
            description = event.get('description', None)
            location = event.get('location', None)
            all_day = event.get('is_all_day_event', False)
            read_only = True
            is_owner = False
            owner = None

            start = parse_datetime(event['start_time'])
            end = parse_datetime(event['end_time'])

            # See if we made the event
            if 'from' in event['from']:
                if event['from'].get('id') == user_id:
                    is_owner = True
                    read_only = False
                else:
                    is_owner = False
                    owner = event['from'].get('name')

            recurrence = event['recurrence'] if event['is_recurrent'] else None

            busy = event['availability'] == 'busy'

            reminder_time = event.get('reminder_time')
            reminders = str([reminder_time] if reminder_time else [])

            participants = []

        except (KeyError, AttributeError):
            raise MalformedEventError()

        stored_uids.append(uid)

        return Event(namespace_id=self.namespace_id,
                     uid=uid,
                     provider_name=self.PROVIDER_NAME,
                     raw_data=raw_data,
                     title=title,
                     description=description,
                     location=location,
                     reminders=reminders,
                     recurrence=recurrence,
                     start=start,
                     end=end,
                     busy=busy,
                     all_day=all_day,
                     read_only=read_only,
                     is_owner=is_owner,
                     owner=owner,
                     source='remote',
                     participants=participants)
Пример #8
0
 def parse_event(self, event, extra):
     if event is None:
         raise MalformedEventError()
     return event