def test_get_credentials(mock_google_env): goauth = GoogleOAuth(database=None) with mock.patch.object(goauth, "authenticate", return_value="patched_access_token"): credentials = goauth.get_credentials() assert credentials.client_id == "test_client_id" assert credentials.client_secret == "test_client_secret" assert credentials.token == "patched_access_token"
def test_poll_for_initial_access_token(mock_google_env, mock_empty_database): goauth = GoogleOAuth(database=mock_empty_database) device = { "device_code": "device_code", "verification_url": "some-google-device-url", "expires_in": time.time() + 3600, "user_code": "ABCD-EFGH", } with mock.patch.object( goauth, "_request_initial_access_token", return_value={"expires_in": 3600} ): token_data = goauth.poll_for_initial_access_token(device) assert token_data == {"expires_in": time.time() + 3600}
def test_ask_for_access(mock_google_env): goauth = GoogleOAuth(database=None) device = { "device_code": "device_code", "verification_url": "some-google-device-url", "expires_in": 3600, "user_code": "ABCD-EFGH", } token_data = {"access_token": "new_access_token"} with requests_mock.mock() as m, mock.patch.object( goauth, "poll_for_initial_access_token", return_value=token_data ): m.post(goauth.GOOGLE_OAUTH_ACCESS_URL, json=device) token = goauth.ask_for_access() assert token == "new_access_token"
def test_request_initial_access_token(mock_google_env): goauth = GoogleOAuth(database=None) device = { "device_code": "device_code", "verification_url": "some-google-device-url", "expires_in": 3600, "user_code": "ABCD-EFGH", } expected_data = { "access_token": "initial_access_token", "refresh_token": "refresh_token", "expires_in": 3600, # TODO (felix): What else? "token_type": "Bearer", } with requests_mock.mock() as m: m.post(goauth.GOOGLE_OAUTH_POLL_URL, json=expected_data) token_data = goauth._request_initial_access_token(device) assert token_data == expected_data
def crawl(module_id: str, app, calendars: List[str], max_items: int = DEFAULT_MAX_ITEMS) -> None: # TODO (felix): Get rid of this, it's only needed to store the oauth token # in GoogleOAuth for the current module. object_key = f"module.{module_id}.data" try: credentials = GoogleOAuth(app.extensions["database"], SCOPES, object_key).get_credentials() except ConnectionError: raise CrawlerDataError("Unable to connect to Google API") if not credentials: raise CrawlerDataError("Unable to authenticate to Google API") # Get the current time to store in the calender events list in the database now = time.time() LOGGER.info("Requesting calendar list from Google API") service = googleapiclient.discovery.build(API_SERVICE_NAME, API_VERSION, credentials=credentials) try: calendar_list = service.calendarList().list().execute() except RefreshError: # Google responds with a RefreshError when the token is invalid as it # would try to refresh the token if the necessary fields are set # which we haven't) raise CrawlerDataError( "Could not retrieve calendar list. Maybe flirror doesn't have " "the permission to access your calendar.") calendar_items = calendar_list.get("items") cals_filtered = [ ci for ci in calendar_items if ci["summary"].lower() in calendars ] if not cals_filtered: raise CrawlerDataError( "None of the provided calendars matched the list I got from Google: {}" .format(calendars)) all_events = [] for cal_item in cals_filtered: # Call the calendar API _now = "{}Z".format( datetime.utcnow().isoformat()) # 'Z' indicates UTC time LOGGER.info( "Requesting upcoming %d events for calendar '%s'", max_items, cal_item["summary"], ) events_result = (service.events().list( calendarId=cal_item["id"], timeMin=_now, maxResults=max_items, singleEvents=True, orderBy="startTime", ).execute()) events = events_result.get("items", []) if not events: LOGGER.warning( "Could not find any upcoming events for calendar '%s", cal_item["summary"], ) for event in events: all_events.append(_parse_event_data(event)) # Sort the events from multiple calendars all_events = sorted(all_events, key=lambda k: k["start"]) event_data = {"_timestamp": now, "events": all_events[:max_items]} app.store_module_data(module_id, event_data)