feat(scouts): add GmailConnector list_labels + stop_watch
This commit is contained in:
@@ -211,3 +211,29 @@ class GmailConnector:
|
|||||||
async def renew_watch(self, scout) -> None:
|
async def renew_watch(self, scout) -> None:
|
||||||
"""Renew an existing Gmail Pub/Sub watch (same as setup_watch)."""
|
"""Renew an existing Gmail Pub/Sub watch (same as setup_watch)."""
|
||||||
await self.setup_watch(scout)
|
await self.setup_watch(scout)
|
||||||
|
|
||||||
|
async def list_labels(self, scout) -> list[dict]:
|
||||||
|
"""Return the account's Gmail labels as [{id, name}]. Empty if no token."""
|
||||||
|
if not scout.oauth_token_encrypted:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _sync() -> list[dict]:
|
||||||
|
service = _get_gmail_service(scout)
|
||||||
|
resp = service.users().labels().list(userId="me").execute()
|
||||||
|
return [{"id": lbl["id"], "name": lbl["name"]} for lbl in resp.get("labels", [])]
|
||||||
|
|
||||||
|
return await asyncio.to_thread(_sync)
|
||||||
|
|
||||||
|
async def stop_watch(self, scout) -> None:
|
||||||
|
"""Stop Gmail push notifications. Swallows errors (watch may be gone)."""
|
||||||
|
if not scout.oauth_token_encrypted:
|
||||||
|
return
|
||||||
|
|
||||||
|
def _sync() -> None:
|
||||||
|
service = _get_gmail_service(scout)
|
||||||
|
service.users().stop(userId="me").execute()
|
||||||
|
|
||||||
|
try:
|
||||||
|
await asyncio.to_thread(_sync)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("stop_watch failed for scout %s", scout.id)
|
||||||
|
|||||||
@@ -82,3 +82,27 @@ async def test_archive_calls_trash():
|
|||||||
with patch("app.scouts.connectors.gmail._get_gmail_service") as mock_svc:
|
with patch("app.scouts.connectors.gmail._get_gmail_service") as mock_svc:
|
||||||
await conn.archive(scout, ItemRef(source_msg_ref="msg-1"))
|
await conn.archive(scout, ItemRef(source_msg_ref="msg-1"))
|
||||||
mock_svc.return_value.users().messages().trash.assert_called()
|
mock_svc.return_value.users().messages().trash.assert_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_list_labels_returns_id_and_name():
|
||||||
|
scout = _make_scout()
|
||||||
|
conn = GmailConnector()
|
||||||
|
fake = {"labels": [
|
||||||
|
{"id": "INBOX", "name": "INBOX", "type": "system"},
|
||||||
|
{"id": "Label_1", "name": "Work", "type": "user"},
|
||||||
|
]}
|
||||||
|
with patch("app.scouts.connectors.gmail._get_gmail_service") as mock_svc:
|
||||||
|
mock_svc.return_value.users().labels().list().execute.return_value = fake
|
||||||
|
labels = await conn.list_labels(scout)
|
||||||
|
assert {"id": "INBOX", "name": "INBOX"} in labels
|
||||||
|
assert {"id": "Label_1", "name": "Work"} in labels
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_stop_watch_calls_stop():
|
||||||
|
scout = _make_scout()
|
||||||
|
conn = GmailConnector()
|
||||||
|
with patch("app.scouts.connectors.gmail._get_gmail_service") as mock_svc:
|
||||||
|
await conn.stop_watch(scout)
|
||||||
|
mock_svc.return_value.users().stop.assert_called()
|
||||||
|
|||||||
Reference in New Issue
Block a user