Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion inbox/api/kellogs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import calendar
import datetime
from json import JSONEncoder, dumps
from json import JSONEncoder, dumps, loads

import arrow # type: ignore[import-untyped]
from flask import Response
Expand Down Expand Up @@ -76,6 +76,24 @@ def format_phone_numbers(phone_numbers): # type: ignore[no-untyped-def] # noqa
return formatted_phone_numbers


def _extract_extended_properties(
raw_data: str | None,
) -> dict[str, dict[str, str]] | None:
"""
Extract extendedProperties from an event's raw_data JSON.

Returns the extendedProperties dict if present, otherwise None.
This is Google Calendar specific data.
"""
if not raw_data:
return None
try:
data = loads(raw_data)
return data.get("extendedProperties")
except (ValueError, TypeError):
return None


def encode( # type: ignore[no-untyped-def] # noqa: ANN201
obj, namespace_public_id=None, expand: bool = False, is_n1: bool = False
):
Expand Down Expand Up @@ -357,6 +375,7 @@ def _get_lowercase_class_name(obj): # type: ignore[no-untyped-def]
"uid": obj.uid,
"calendar_event_link": obj.calendar_event_link,
"conference_data": obj.conference_data,
"extended_properties": _extract_extended_properties(obj.raw_data),
}
if isinstance(obj, RecurringEvent):
resp["recurrence"] = {
Expand Down
75 changes: 74 additions & 1 deletion tests/events/test_google_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pytest
import requests

from inbox.api.kellogs import _encode
from inbox.api.kellogs import _encode, _extract_extended_properties
from inbox.events.google import GoogleEventsProvider, parse_event_response
from inbox.exceptions import AccessNotEnabledError
from inbox.models import Calendar, Event
Expand Down Expand Up @@ -859,3 +859,76 @@ def test_cancelled_override_creation() -> None:
provider._get_raw_events = mock.MagicMock(return_value=raw_response)
updates = provider.sync_events("uid", 1)
assert updates[0].cancelled is True


class TestExtractExtendedProperties:
"""Tests for the _extract_extended_properties helper function."""

def test_returns_none_for_none_raw_data(self) -> None:
assert _extract_extended_properties(None) is None

def test_returns_none_for_empty_raw_data(self) -> None:
assert _extract_extended_properties("") is None

def test_returns_none_for_invalid_json(self) -> None:
assert _extract_extended_properties("not valid json") is None

def test_returns_none_when_extended_properties_not_present(self) -> None:
raw_data = json.dumps({"id": "test", "summary": "Test Event"})
assert _extract_extended_properties(raw_data) is None

def test_returns_extended_properties(self) -> None:
raw_data = json.dumps(
{
"id": "test",
"extendedProperties": {"private": {"key1": "value1"}},
}
)
result = _extract_extended_properties(raw_data)
assert result == {"private": {"key1": "value1"}}


@pytest.mark.parametrize(
("raw_extended_properties", "expected_extended_properties"),
[
({}, None),
(
{"extendedProperties": {"private": {"closeTaskId": "task_123"}}},
{"private": {"closeTaskId": "task_123"}},
),
],
)
def test_event_with_extended_properties(
raw_extended_properties, expected_extended_properties
) -> None:
raw_event = {
"created": "2014-01-09T03:33:02.000Z",
"creator": {
"displayName": "Ben Bitdiddle",
"email": "ben.bitdiddle2222@gmail.com",
"self": True,
},
"etag": '"2778476764000000"',
"htmlLink": "https://www.google.com/calendar/event?eid=BAR",
"iCalUID": "20140615_60o30dr564o30c1g60o30dr4ck@google.com",
"id": "20140615_60o30dr564o30c1g60o30dr4ck",
"kind": "calendar#event",
"organizer": {
"displayName": "Ben Bitdiddle",
"email": "ben.bitdiddle2222@gmail.com",
"self": True,
},
"sequence": 0,
"start": {"date": "2014-03-15"},
"end": {"date": "2014-03-15"},
"status": "confirmed",
"summary": "Event with Extended Properties",
"transparency": "transparent",
"updated": "2014-01-09T03:33:02.000Z",
"visibility": "public",
**raw_extended_properties,
}

event = parse_event_response(raw_event, True)
encoded = _encode(event, "999999")
assert encoded["extended_properties"] == expected_extended_properties