From 7a5803beccd27157094e3bfe881a2a52f282c5e6 Mon Sep 17 00:00:00 2001 From: Hamza Date: Thu, 16 Jan 2025 16:30:52 +0100 Subject: [PATCH] feat: add prolific integration (M2-8325) --- src/apps/integrations/domain.py | 1 + src/apps/integrations/prolific/__init__.py | 0 src/apps/integrations/prolific/domain.py | 17 ++++++++ .../integrations/prolific/service/__init__.py | 0 .../integrations/prolific/service/prolific.py | 39 +++++++++++++++++++ src/apps/integrations/service/integrations.py | 25 ++++++++++++ 6 files changed, 82 insertions(+) create mode 100644 src/apps/integrations/prolific/__init__.py create mode 100644 src/apps/integrations/prolific/domain.py create mode 100644 src/apps/integrations/prolific/service/__init__.py create mode 100644 src/apps/integrations/prolific/service/prolific.py diff --git a/src/apps/integrations/domain.py b/src/apps/integrations/domain.py index 3372d6031eb..7dd20e8237e 100644 --- a/src/apps/integrations/domain.py +++ b/src/apps/integrations/domain.py @@ -9,6 +9,7 @@ class AvailableIntegrations(str, Enum): LORIS = "LORIS" + PROLIFIC = "PROLIFIC" FUTURE = "FUTURE" diff --git a/src/apps/integrations/prolific/__init__.py b/src/apps/integrations/prolific/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/apps/integrations/prolific/domain.py b/src/apps/integrations/prolific/domain.py new file mode 100644 index 00000000000..bf6c38fedbc --- /dev/null +++ b/src/apps/integrations/prolific/domain.py @@ -0,0 +1,17 @@ +import json + +from pydantic import BaseModel + +from apps.integrations.db.schemas import IntegrationsSchema + + +class ProlificIntegration(BaseModel): + api_key: str + + @classmethod + def from_schema(cls, schema: IntegrationsSchema): + configuration = json.loads(schema.configuration.replace("'", '"')) + return cls(api_key=configuration["api_key"]) + + def __repr__(self): + return "ProlificIntegration()" diff --git a/src/apps/integrations/prolific/service/__init__.py b/src/apps/integrations/prolific/service/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/apps/integrations/prolific/service/prolific.py b/src/apps/integrations/prolific/service/prolific.py new file mode 100644 index 00000000000..781274de13e --- /dev/null +++ b/src/apps/integrations/prolific/service/prolific.py @@ -0,0 +1,39 @@ +import uuid + +import requests +from fastapi import HTTPException + +from apps.integrations.crud.integrations import IntegrationsCRUD +from apps.integrations.db.schemas import IntegrationsSchema +from apps.integrations.domain import AvailableIntegrations +from apps.integrations.prolific.domain import ProlificIntegration +from apps.users.domain import User + + +class ProlificIntegrationService: + def __init__(self, applet_id: uuid.UUID, session, user: User) -> None: + self.applet_id = applet_id + self.session = session + self.user = user + self.type = AvailableIntegrations.PROLIFIC + + async def create_prolific_integration(self, api_key: str) -> ProlificIntegration: + prolific_response = requests.get( + "https://api.prolific.com/api/v1/users/me/", + headers={"Authorization": f"Token {api_key}", "Content-Type": "application/json"}, + ) + + if prolific_response.status_code != 200: + raise HTTPException(status_code=prolific_response.status_code, detail="Prolific token is invalid") + + integration_schema = await IntegrationsCRUD(self.session).create( + IntegrationsSchema( + applet_id=self.applet_id, + type=self.type, + configuration={ + "api_key": api_key, + }, + ) + ) + + return ProlificIntegration.from_schema(integration_schema) diff --git a/src/apps/integrations/service/integrations.py b/src/apps/integrations/service/integrations.py index c85442b36ac..33d63ff8b44 100644 --- a/src/apps/integrations/service/integrations.py +++ b/src/apps/integrations/service/integrations.py @@ -7,6 +7,7 @@ ) from apps.integrations.loris.domain.loris_integrations import LorisIntegrationPublic from apps.integrations.loris.service.loris import LorisIntegrationService +from apps.integrations.prolific.service.prolific import ProlificIntegrationService from apps.integrations.service.future_integration import FutureIntegrationService from apps.users.domain import User @@ -43,6 +44,24 @@ async def create_integration(self, newIntegration: Integration) -> Integration: applet_id=newIntegration.applet_id, configuration=loris_integration, ) + case AvailableIntegrations.PROLIFIC: + expected_keys = ["api_key"] + if None in [newIntegration.configuration.get(k, None) for k in expected_keys]: + raise UnexpectedPropertiesForIntegration( + provided_keys=list(newIntegration.configuration.keys()), + expected_keys=expected_keys, + integration_type=AvailableIntegrations.PROLIFIC, + ) + prolific_integration = await ProlificIntegrationService( + newIntegration.applet_id, + self.session, + self.user, + ).create_prolific_integration(api_key=newIntegration.configuration["api_key"]) + return Integration( + integration_type=AvailableIntegrations.PROLIFIC, + applet_id=newIntegration.applet_id, + configuration=prolific_integration, + ) case AvailableIntegrations.FUTURE: expected_keys = ["endpoint", "api_key"] if None in [newIntegration.configuration.get(k, None) for k in expected_keys]: @@ -82,6 +101,12 @@ async def retrieve_integration(self, applet_id, integration_type) -> Integration applet_id=applet_id, configuration=loris_integration, ) + case AvailableIntegrations.PROLIFIC: + return Integration( + integration_type=AvailableIntegrations.PROLIFIC, + applet_id=applet_id, + configuration={}, # Configuration is empty as we don't want to share the api_key + ) case AvailableIntegrations.FUTURE: future_integration = FutureIntegrationPublic.from_schema(integration_schema) return Integration(