# # Copyright (c) 2023 Airbyte, Inc., all rights reserved. # from abc import ABC from typing import Any, Iterable, List, Mapping, MutableMapping, Optional import pendulum import requests from airbyte_cdk.models import SyncMode from airbyte_cdk.sources.streams.http import HttpStream class QualarooStream(HttpStream, ABC): url_base = "https://api.qualaroo.com/api/v1/" # Define primary key as sort key for full_refresh, or very first sync for incremental_refresh primary_key = "id" # Page size limit = 500 extra_params = None def __init__(self, start_date: pendulum.datetime, survey_ids: List[str] = [], **kwargs): super().__init__(**kwargs) self._start_date = start_date self._survey_ids = survey_ids self._offset = 0 def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]: resp_json = response.json() if len(resp_json) == 500: self._offset += 500 return {"offset": self._offset} def request_params( self, stream_state: Mapping[str, Any], stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None ) -> MutableMapping[str, Any]: params = {"limit": self.limit, "start_date": self._start_date} if next_page_token: params.update(**next_page_token) if self.extra_params: params.update(self.extra_params) return params def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]: json_response = response.json() for record in json_response: yield record class ChildStreamMixin: parent_stream_class: Optional[QualarooStream] = None def stream_slices(self, sync_mode, **kwargs) -> Iterable[Optional[Mapping[str, any]]]: for item in self.parent_stream_class(config=self.config).read_records(sync_mode=sync_mode): yield {"id": item["id"]} class Surveys(QualarooStream): """Return list of all Surveys. API Docs: https://help.qualaroo.com/hc/en-us/articles/201969438-The-REST-Reporting-API Endpoint: https://api.qualaroo.com/api/v1/nudges/ """ def path(self, stream_slice: Mapping[str, Any] = None, **kwargs) -> str: return "nudges" def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]: survey_ids = self._survey_ids result = super().parse_response(response=response, **kwargs) for record in result: if not survey_ids or str(record["id"]) in survey_ids: yield record class Responses(ChildStreamMixin, QualarooStream): """Return list of all responses of a survey. API Docs: hhttps://help.qualaroo.com/hc/en-us/articles/201969438-The-REST-Reporting-API Endpoint: https://api.qualaroo.com/api/v1/nudges//responses.json """ parent_stream_class = Surveys def path(self, stream_slice: Mapping[str, Any] = None, **kwargs) -> str: survey_id = stream_slice["survey_id"] return f"nudges/{survey_id}/responses.json" def stream_slices(self, **kwargs): survey_stream = Surveys(start_date=self._start_date, survey_ids=self._survey_ids, authenticator=self.authenticator) for survey in survey_stream.read_records(sync_mode=SyncMode.full_refresh): yield {"survey_id": survey["id"]} def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]: response_data = response.json() # de-nest the answered_questions object if exists for rec in response_data: if "answered_questions" in rec: rec["answered_questions"] = list(rec["answered_questions"].values()) yield from response_data