-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat:(Loris): Endpoints for enabling and disabling integration for wo…
- Loading branch information
Showing
15 changed files
with
269 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from apps.integrations.api.integrations import * # noqa: F401, F403 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from fastapi import Body, Depends | ||
|
||
from apps.authentication.deps import get_current_user | ||
from apps.integrations.domain import Integration, IntegrationFilter | ||
from apps.integrations.service import IntegrationService | ||
from apps.shared.domain import ResponseMulti | ||
from apps.shared.query_params import QueryParams, parse_query_params | ||
from apps.users.domain import User | ||
from infrastructure.database import atomic | ||
from infrastructure.database.deps import get_session | ||
|
||
__all__ = ["enable_integration", "disable_integration"] | ||
|
||
|
||
async def enable_integration( | ||
user: User = Depends(get_current_user), | ||
session=Depends(get_session), | ||
integrations: list[Integration] = Body(...), | ||
) -> ResponseMulti[Integration]: | ||
async with atomic(session): | ||
integrations = await IntegrationService(session, user).enable_integration(integrations) | ||
return ResponseMulti(result=integrations, count=len(integrations)) | ||
|
||
|
||
async def disable_integration( | ||
user: User = Depends(get_current_user), | ||
session=Depends(get_session), | ||
query_params: QueryParams = Depends(parse_query_params(IntegrationFilter)), | ||
): | ||
async with atomic(session): | ||
await IntegrationService(session, user).disable_integration(query_params) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from enum import Enum | ||
|
||
from apps.shared.domain import InternalModel | ||
|
||
|
||
class AvailableIntegrations(str, Enum): | ||
LORIS = "LORIS" | ||
|
||
|
||
class Integration(InternalModel): | ||
integration_type: AvailableIntegrations | ||
|
||
|
||
class IntegrationFilter(InternalModel): | ||
integration_types: list[AvailableIntegrations] | None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from gettext import gettext as _ | ||
|
||
from apps.shared.exception import ValidationError | ||
|
||
|
||
class UniqueIntegrationError(ValidationError): | ||
message = _("Integrations must be unique.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from fastapi.routing import APIRouter | ||
from starlette import status | ||
|
||
from apps.integrations.api import disable_integration, enable_integration | ||
from apps.shared.domain.response import AUTHENTICATION_ERROR_RESPONSES, DEFAULT_OPENAPI_RESPONSE | ||
|
||
router = APIRouter(prefix="/integrations", tags=["Integration"]) | ||
|
||
|
||
router.post( | ||
"/", | ||
description="This endpoint is used to enable integration\ | ||
options for a workspace", | ||
status_code=status.HTTP_200_OK, | ||
responses={ | ||
**DEFAULT_OPENAPI_RESPONSE, | ||
**AUTHENTICATION_ERROR_RESPONSES, | ||
}, | ||
)(enable_integration) | ||
|
||
router.delete( | ||
"/", | ||
description="This endpoint is used to remove integrations\ | ||
from a workspace", | ||
status_code=status.HTTP_204_NO_CONTENT, | ||
responses={ | ||
**DEFAULT_OPENAPI_RESPONSE, | ||
**AUTHENTICATION_ERROR_RESPONSES, | ||
}, | ||
)(disable_integration) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from apps.integrations.service.integrations import * # noqa: F401, F403 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from apps.integrations.domain import AvailableIntegrations, Integration | ||
from apps.integrations.errors import UniqueIntegrationError | ||
from apps.shared.query_params import QueryParams | ||
from apps.users.domain import User | ||
from apps.workspaces.crud.workspaces import UserWorkspaceCRUD | ||
|
||
__all__ = [ | ||
"IntegrationService", | ||
] | ||
|
||
|
||
class IntegrationService: | ||
def __init__(self, session, user: User) -> None: | ||
self.session = session | ||
self.user = user | ||
|
||
async def enable_integration(self, integrations: list[Integration]): | ||
workspace = await UserWorkspaceCRUD(self.session).get_by_user_id(user_id_=self.user.id) | ||
integration_names: list[AvailableIntegrations] = [integration.integration_type for integration in integrations] | ||
if len(set(integration_names)) != len(integration_names): | ||
raise UniqueIntegrationError() | ||
|
||
workspace.integrations = [integration.dict() for integration in integrations] | ||
workspace = await UserWorkspaceCRUD(self.session).save(workspace) | ||
return [Integration.parse_obj(integration) for integration in workspace.integrations] | ||
|
||
async def disable_integration(self, query: QueryParams): | ||
workspace = await UserWorkspaceCRUD(self.session).get_by_user_id(user_id_=self.user.id) | ||
print(query) | ||
if query.filters: | ||
workspace.integrations = ( | ||
[ | ||
integration | ||
for integration in workspace.integrations | ||
if integration["integration_type"] not in query.filters["integration_types"] | ||
] | ||
if workspace.integrations | ||
else workspace.integrations | ||
) | ||
else: | ||
workspace.integrations = None | ||
await UserWorkspaceCRUD(self.session).save(workspace) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
from apps.integrations.errors import UniqueIntegrationError | ||
from apps.integrations.router import router as integration_router | ||
from apps.shared.test import BaseTest | ||
from apps.shared.test.client import TestClient | ||
from apps.users.domain import User | ||
|
||
|
||
class TestIntegrationRouter(BaseTest): | ||
fixtures = [ | ||
"workspaces/fixtures/workspaces.json", | ||
] | ||
enable_integration_url = integration_router.url_path_for("enable_integration") | ||
disable_integration_url = integration_router.url_path_for("disable_integration") | ||
|
||
async def test_enable_integration( | ||
self, | ||
client: TestClient, | ||
tom: User, | ||
): | ||
integration_data = [ | ||
{"integrationType": "LORIS"}, | ||
] | ||
client.login(tom) | ||
response = await client.post(self.enable_integration_url, data=integration_data) | ||
assert response.status_code == 200 | ||
|
||
async def test_disable_integration( | ||
self, | ||
client: TestClient, | ||
tom: User, | ||
): | ||
client.login(tom) | ||
response = await client.delete( | ||
self.disable_integration_url, | ||
) | ||
assert response.status_code == 204 | ||
|
||
async def test_enable_integration_unique_error( | ||
self, | ||
client: TestClient, | ||
tom: User, | ||
): | ||
integration_data = [ | ||
{"integrationType": "LORIS"}, | ||
{"integrationType": "LORIS"}, | ||
] | ||
client.login(tom) | ||
response = await client.post(self.enable_integration_url, data=integration_data) | ||
assert response.status_code == 400 | ||
|
||
result = response.json()["result"] | ||
assert len(result) == 1 | ||
assert result[0]["message"] == UniqueIntegrationError.message |
19 changes: 19 additions & 0 deletions
19
src/apps/integrations/tests/unit/domain/test_integration.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import pytest | ||
|
||
from apps.integrations.domain import Integration | ||
|
||
|
||
def test_integration_model(): | ||
integration_data = { | ||
"integration_type": "LORIS", | ||
} | ||
item = Integration(**integration_data) | ||
assert item.integration_type == integration_data["integration_type"] | ||
|
||
|
||
def test_integration_model_error(): | ||
integration_data = { | ||
"integration_type": "MORRIS", | ||
} | ||
with pytest.raises(Exception): | ||
Integration(**integration_data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
...cture/database/migrations/versions/2024_06_17_15_46-change_integrations_field_type_in_.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"""Change integrations field type in workspaces table | ||
Revision ID: d877f29be2f0 | ||
Revises: 70c50aba13b7 | ||
Create Date: 2024-06-17 15:46:33.965375 | ||
""" | ||
import sqlalchemy as sa | ||
from alembic import op | ||
from sqlalchemy.dialects import postgresql | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = "d877f29be2f0" | ||
down_revision = "70c50aba13b7" | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.alter_column("users_workspaces", "integrations", type_=postgresql.JSONB(astext_type=sa.Text()),postgresql_using="array_to_json(integrations);") | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_column("users_workspaces", "integrations") | ||
|
||
op.add_column( | ||
"users_workspaces", | ||
sa.Column( | ||
"integrations", | ||
sa.ARRAY(sa.String(length=32)), | ||
|
||
nullable=True, | ||
), | ||
) | ||
# ### end Alembic commands ### |