From 70b676865e42b304bfa9ecc7455355540f53a4d5 Mon Sep 17 00:00:00 2001 From: Catherine Smith Date: Wed, 17 Jul 2024 00:42:54 +0200 Subject: [PATCH] PROD-2211 moves some property-specific endpoints from OSS -> plus (#5069) --- CHANGELOG.md | 5 + clients/admin-ui/cypress/e2e/messaging.cy.ts | 6 +- .../messaging-templates.slice.plus.ts | 68 +++ .../messaging-templates.slice.ts | 58 +-- .../useMessagingTemplateToggle.tsx | 2 +- clients/admin-ui/src/pages/messaging/[id].tsx | 2 +- .../src/pages/messaging/add-template.tsx | 2 +- .../admin-ui/src/pages/messaging/index.tsx | 2 +- .../api/v1/endpoints/messaging_endpoints.py | 126 +---- .../v1/endpoints/test_messaging_endpoints.py | 446 ------------------ 10 files changed, 83 insertions(+), 634 deletions(-) create mode 100644 clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.plus.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a077e995e..44d4b15c28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ The types of changes are: - `Fixed` for any bug fixes. - `Security` in case of vulnerabilities. +## [Unreleased](https://github.com/ethyca/fides/compare/2.41.0...main) + +### Changed +- Moves some endpoints for property-specific messaging from OSS -> plus [#5069](https://github.com/ethyca/fides/pull/5069) + ## [2.41.0](https://github.com/ethyca/fides/compare/2.40.0...2.41.0) ### Added diff --git a/clients/admin-ui/cypress/e2e/messaging.cy.ts b/clients/admin-ui/cypress/e2e/messaging.cy.ts index a873029652..0eeb7da3c6 100644 --- a/clients/admin-ui/cypress/e2e/messaging.cy.ts +++ b/clients/admin-ui/cypress/e2e/messaging.cy.ts @@ -8,7 +8,7 @@ describe("Messaging", () => { cy.login(); stubPlus(true); - cy.intercept("/api/v1/messaging/templates/summary?*", { + cy.intercept("/api/v1/plus/messaging/templates/summary?*", { fixture: "messaging/summary.json", }).as("getEmailTemplatesSummary"); @@ -20,13 +20,13 @@ describe("Messaging", () => { fixture: "properties/properties.json", }).as("getProperties"); - cy.intercept("PATCH", "/api/v1/messaging/templates/*", {}).as( + cy.intercept("PATCH", "/api/v1/plus/messaging/templates/*", {}).as( "patchTemplate" ); cy.intercept( "POST", - "/api/v1/messaging/templates/privacy_request_complete_access", + "/api/v1/plus/messaging/templates/privacy_request_complete_access", {} ).as("postTemplate"); }); diff --git a/clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.plus.ts b/clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.plus.ts new file mode 100644 index 0000000000..3d05cba9a6 --- /dev/null +++ b/clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.plus.ts @@ -0,0 +1,68 @@ +import { baseApi } from "common/api.slice"; + +import { + MessagingTemplateCreate, + MessagingTemplatePatch, + MessagingTemplateResponse, + MessagingTemplateUpdate, +} from "~/features/messaging-templates/messaging-templates.slice"; +import { Page_MessagingTemplateWithPropertiesSummary_ } from "~/types/api"; + +const messagingTemplatesPlusApi = baseApi.injectEndpoints({ + endpoints: (build) => ({ + getSummaryMessagingTemplates: build.query< + Page_MessagingTemplateWithPropertiesSummary_, + any + >({ + query: (params) => ({ + method: "GET", + url: `plus/messaging/templates/summary`, + params, + }), + providesTags: () => ["Property-Specific Messaging Templates"], + }), + // Full update existing template + putMessagingTemplateById: build.mutation< + MessagingTemplateResponse, + MessagingTemplateUpdate + >({ + query: ({ templateId, template }) => ({ + url: `plus/messaging/templates/${templateId}`, + method: "PUT", + body: template, + }), + invalidatesTags: () => ["Property-Specific Messaging Templates"], + }), + // Partial update existing template, e.g. enable it + patchMessagingTemplateById: build.mutation< + MessagingTemplateResponse, + MessagingTemplatePatch + >({ + query: ({ templateId, template }) => ({ + url: `plus/messaging/templates/${templateId}`, + method: "PATCH", + body: template, + }), + invalidatesTags: () => ["Property-Specific Messaging Templates"], + }), + // endpoint for creating new messaging template- POST by type + createMessagingTemplateByType: build.mutation< + MessagingTemplateResponse, + MessagingTemplateCreate + >({ + query: ({ templateType, template }) => ({ + url: `plus/messaging/templates/${templateType}`, + method: "POST", + body: template, + }), + invalidatesTags: () => ["Property-Specific Messaging Templates"], + }), + }), +}); + +export const { + useGetSummaryMessagingTemplatesQuery, + usePutMessagingTemplateByIdMutation, + useCreateMessagingTemplateByTypeMutation, + usePatchMessagingTemplateByIdMutation, +} = messagingTemplatesPlusApi; diff --git a/clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.ts b/clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.ts index f437cebb31..722159ebe1 100644 --- a/clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.ts +++ b/clients/admin-ui/src/features/messaging-templates/messaging-templates.slice.ts @@ -1,8 +1,5 @@ import { baseApi } from "~/features/common/api.slice"; -import { - MinimalProperty, - Page_MessagingTemplateWithPropertiesSummary_, -} from "~/types/api"; +import { MinimalProperty } from "~/types/api"; import { BulkUpdateFailed } from "~/types/api/models/BulkUpdateFailed"; export type MessagingTemplate = { @@ -70,17 +67,6 @@ const messagingTemplatesApi = baseApi.injectEndpoints({ query: () => ({ url: `messaging/templates` }), providesTags: () => ["Messaging Templates"], }), - getSummaryMessagingTemplates: build.query< - Page_MessagingTemplateWithPropertiesSummary_, - any - >({ - query: (params) => ({ - method: "GET", - url: `messaging/templates/summary`, - params, - }), - providesTags: () => ["Property-Specific Messaging Templates"], - }), updateMessagingTemplates: build.mutation< BulkPutMessagingTemplateResponse, MessagingTemplate[] @@ -90,7 +76,7 @@ const messagingTemplatesApi = baseApi.injectEndpoints({ method: "PUT", body: templates, }), - invalidatesTags: () => ["Property-Specific Messaging Templates"], + invalidatesTags: () => ["Messaging Templates"], }), // Render data from existing template- GET by id getMessagingTemplateById: build.query({ @@ -99,30 +85,6 @@ const messagingTemplatesApi = baseApi.injectEndpoints({ }), providesTags: () => ["Property-Specific Messaging Templates"], }), - // Update existing template - putMessagingTemplateById: build.mutation< - MessagingTemplateResponse, - MessagingTemplateUpdate - >({ - query: ({ templateId, template }) => ({ - url: `/messaging/templates/${templateId}`, - method: "PUT", - body: template, - }), - invalidatesTags: () => ["Property-Specific Messaging Templates"], - }), - // Update existing template - patchMessagingTemplateById: build.mutation< - MessagingTemplateResponse, - MessagingTemplatePatch - >({ - query: ({ templateId, template }) => ({ - url: `/messaging/templates/${templateId}`, - method: "PATCH", - body: template, - }), - invalidatesTags: () => ["Property-Specific Messaging Templates"], - }), // endpoint for rendering data for default template- GET by type getMessagingTemplateDefault: build.query< MessagingTemplateDefaultResponse, @@ -132,18 +94,6 @@ const messagingTemplatesApi = baseApi.injectEndpoints({ url: `/messaging/templates/default/${templateType}`, }), }), - // endpoint for creating new messaging template- POST by type - createMessagingTemplateByType: build.mutation< - MessagingTemplateResponse, - MessagingTemplateCreate - >({ - query: ({ templateType, template }) => ({ - url: `/messaging/templates/${templateType}`, - method: "POST", - body: template, - }), - invalidatesTags: () => ["Property-Specific Messaging Templates"], - }), // delete template by id deleteMessagingTemplateById: build.mutation({ query: (templateId: string) => ({ @@ -158,11 +108,7 @@ const messagingTemplatesApi = baseApi.injectEndpoints({ export const { useGetMessagingTemplatesQuery, useUpdateMessagingTemplatesMutation, - useGetSummaryMessagingTemplatesQuery, useGetMessagingTemplateByIdQuery, - usePutMessagingTemplateByIdMutation, useGetMessagingTemplateDefaultQuery, - useCreateMessagingTemplateByTypeMutation, useDeleteMessagingTemplateByIdMutation, - usePatchMessagingTemplateByIdMutation, } = messagingTemplatesApi; diff --git a/clients/admin-ui/src/features/messaging-templates/useMessagingTemplateToggle.tsx b/clients/admin-ui/src/features/messaging-templates/useMessagingTemplateToggle.tsx index 9424d59afe..1ce90998b3 100644 --- a/clients/admin-ui/src/features/messaging-templates/useMessagingTemplateToggle.tsx +++ b/clients/admin-ui/src/features/messaging-templates/useMessagingTemplateToggle.tsx @@ -3,7 +3,7 @@ import { useToast } from "fidesui"; import { useCallback } from "react"; import { errorToastParams, successToastParams } from "~/features/common/toast"; -import { usePatchMessagingTemplateByIdMutation } from "~/features/messaging-templates/messaging-templates.slice"; +import { usePatchMessagingTemplateByIdMutation } from "~/features/messaging-templates/messaging-templates.slice.plus"; import { isErrorResult } from "~/types/errors"; const useMessagingTemplateToggle = () => { diff --git a/clients/admin-ui/src/pages/messaging/[id].tsx b/clients/admin-ui/src/pages/messaging/[id].tsx index 7482189907..59eeea4d6b 100644 --- a/clients/admin-ui/src/pages/messaging/[id].tsx +++ b/clients/admin-ui/src/pages/messaging/[id].tsx @@ -18,8 +18,8 @@ import { MessagingTemplateCreateOrUpdate, useDeleteMessagingTemplateByIdMutation, useGetMessagingTemplateByIdQuery, - usePutMessagingTemplateByIdMutation, } from "~/features/messaging-templates/messaging-templates.slice"; +import { usePutMessagingTemplateByIdMutation } from "~/features/messaging-templates/messaging-templates.slice.plus"; import PropertySpecificMessagingTemplateForm, { FormValues, } from "~/features/messaging-templates/PropertySpecificMessagingTemplateForm"; diff --git a/clients/admin-ui/src/pages/messaging/add-template.tsx b/clients/admin-ui/src/pages/messaging/add-template.tsx index 5e60c56ee4..c39b34d983 100644 --- a/clients/admin-ui/src/pages/messaging/add-template.tsx +++ b/clients/admin-ui/src/pages/messaging/add-template.tsx @@ -8,9 +8,9 @@ import Layout from "~/features/common/Layout"; import { errorToastParams, successToastParams } from "~/features/common/toast"; import { MessagingTemplateCreateOrUpdate, - useCreateMessagingTemplateByTypeMutation, useGetMessagingTemplateDefaultQuery, } from "~/features/messaging-templates/messaging-templates.slice"; +import { useCreateMessagingTemplateByTypeMutation } from "~/features/messaging-templates/messaging-templates.slice.plus"; import PropertySpecificMessagingTemplateForm, { FormValues, } from "~/features/messaging-templates/PropertySpecificMessagingTemplateForm"; diff --git a/clients/admin-ui/src/pages/messaging/index.tsx b/clients/admin-ui/src/pages/messaging/index.tsx index ca984e9a2b..428976625a 100644 --- a/clients/admin-ui/src/pages/messaging/index.tsx +++ b/clients/admin-ui/src/pages/messaging/index.tsx @@ -35,7 +35,7 @@ import { PaginationBar } from "~/features/common/table/v2/PaginationBar"; import AddMessagingTemplateModal from "~/features/messaging-templates/AddMessagingTemplateModal"; import { CustomizableMessagingTemplatesEnum } from "~/features/messaging-templates/CustomizableMessagingTemplatesEnum"; import CustomizableMessagingTemplatesLabelEnum from "~/features/messaging-templates/CustomizableMessagingTemplatesLabelEnum"; -import { useGetSummaryMessagingTemplatesQuery } from "~/features/messaging-templates/messaging-templates.slice"; +import { useGetSummaryMessagingTemplatesQuery } from "~/features/messaging-templates/messaging-templates.slice.plus"; import useMessagingTemplateToggle from "~/features/messaging-templates/useMessagingTemplateToggle"; import { useGetConfigurationSettingsQuery } from "~/features/privacy-requests"; import { useGetAllPropertiesQuery } from "~/features/properties"; diff --git a/src/fides/api/api/v1/endpoints/messaging_endpoints.py b/src/fides/api/api/v1/endpoints/messaging_endpoints.py index d721cd067e..a31383d5e6 100644 --- a/src/fides/api/api/v1/endpoints/messaging_endpoints.py +++ b/src/fides/api/api/v1/endpoints/messaging_endpoints.py @@ -31,10 +31,7 @@ get_messaging_method, get_schema_for_secrets, ) -from fides.api.models.messaging_template import ( - DEFAULT_MESSAGING_TEMPLATES, - MessagingTemplate, -) +from fides.api.models.messaging_template import DEFAULT_MESSAGING_TEMPLATES from fides.api.oauth.utils import verify_oauth_client from fides.api.schemas.api import BulkUpdateFailed from fides.api.schemas.messaging.messaging import ( @@ -50,10 +47,7 @@ MessagingMethod, MessagingServiceType, MessagingTemplateDefault, - MessagingTemplateWithPropertiesBodyParams, MessagingTemplateWithPropertiesDetail, - MessagingTemplateWithPropertiesPatchBodyParams, - MessagingTemplateWithPropertiesSummary, TestMessagingStatusMessage, UserEmailInviteStatus, ) @@ -65,17 +59,13 @@ from fides.api.service.messaging.messaging_crud_service import ( create_or_update_basic_templates, create_or_update_messaging_config, - create_property_specific_template_by_type, delete_messaging_config, delete_template_by_id, get_all_basic_messaging_templates, get_default_template_by_type, get_messaging_config_by_key, get_template_by_id, - patch_property_specific_template, - save_defaults_for_all_messaging_template_types, update_messaging_config, - update_property_specific_template, ) from fides.api.util.api_router import APIRouter from fides.api.util.logger import Pii @@ -98,8 +88,6 @@ MESSAGING_STATUS, MESSAGING_TEMPLATE_BY_ID, MESSAGING_TEMPLATE_DEFAULT_BY_TEMPLATE_TYPE, - MESSAGING_TEMPLATES_BY_TEMPLATE_TYPE, - MESSAGING_TEMPLATES_SUMMARY, MESSAGING_TEST, V1_URL_PREFIX, ) @@ -606,29 +594,6 @@ def update_basic_messaging_templates( return BulkPutBasicMessagingTemplateResponse(succeeded=succeeded, failed=failed) -@router.get( - MESSAGING_TEMPLATES_SUMMARY, - dependencies=[Security(verify_oauth_client, scopes=[MESSAGING_TEMPLATE_UPDATE])], - response_model=Page[MessagingTemplateWithPropertiesSummary], -) -def get_property_specific_messaging_templates_summary( - *, db: Session = Depends(deps.get_db), params: Params = Depends() -) -> AbstractPage[MessagingTemplate]: - """ - Returns all messaging templates, automatically saving any missing message template types to the db. - """ - # First save any missing template types to db - save_defaults_for_all_messaging_template_types(db) - ordered_templates = MessagingTemplate.query(db=db).order_by( - MessagingTemplate.created_at.desc() - ) - # Now return all templates - return paginate( - ordered_templates, - params=params, - ) - - @router.get( MESSAGING_TEMPLATE_DEFAULT_BY_TEMPLATE_TYPE, dependencies=[Security(verify_oauth_client, scopes=[MESSAGING_TEMPLATE_UPDATE])], @@ -652,95 +617,6 @@ def get_default_messaging_template( ) -@router.post( - MESSAGING_TEMPLATES_BY_TEMPLATE_TYPE, - dependencies=[Security(verify_oauth_client, scopes=[MESSAGING_TEMPLATE_UPDATE])], - response_model=Optional[MessagingTemplateWithPropertiesDetail], -) -def create_property_specific_messaging_template( - template_type: MessagingActionType, - *, - db: Session = Depends(deps.get_db), - messaging_template_create_body: MessagingTemplateWithPropertiesBodyParams, -) -> Optional[MessagingTemplate]: - """ - Creates property-specific messaging template by template type. - """ - logger.info( - "Creating new property-specific messaging template of type '{}'", template_type - ) - try: - return create_property_specific_template_by_type( - db, template_type, messaging_template_create_body - ) - except MessagingTemplateValidationException as e: - raise HTTPException( - status_code=HTTP_400_BAD_REQUEST, - detail=e.message, - ) - - -@router.put( - MESSAGING_TEMPLATE_BY_ID, - dependencies=[Security(verify_oauth_client, scopes=[MESSAGING_TEMPLATE_UPDATE])], - response_model=Optional[MessagingTemplateWithPropertiesDetail], -) -def update_property_specific_messaging_template( - template_id: str, - *, - db: Session = Depends(deps.get_db), - messaging_template_update_body: MessagingTemplateWithPropertiesBodyParams, -) -> Optional[MessagingTemplate]: - """ - Updates property-specific messaging template by template id. - """ - logger.info("Updating property-specific messaging template of id '{}'", template_id) - try: - return update_property_specific_template( - db, template_id, messaging_template_update_body - ) - except EmailTemplateNotFoundException as e: - raise HTTPException( - status_code=HTTP_404_NOT_FOUND, - detail=e.message, - ) - except MessagingTemplateValidationException as e: - raise HTTPException( - status_code=HTTP_400_BAD_REQUEST, - detail=e.message, - ) - - -@router.patch( - MESSAGING_TEMPLATE_BY_ID, - dependencies=[Security(verify_oauth_client, scopes=[MESSAGING_TEMPLATE_UPDATE])], - response_model=Optional[MessagingTemplateWithPropertiesDetail], -) -def patch_property_specific_messaging_template( - template_id: str, - *, - db: Session = Depends(deps.get_db), - messaging_template_update_body: MessagingTemplateWithPropertiesPatchBodyParams, -) -> Optional[MessagingTemplate]: - """ - Updates property-specific messaging template by template id. - """ - logger.info("Patching property-specific messaging template of id '{}'", template_id) - try: - data = messaging_template_update_body.dict(exclude_none=True) - return patch_property_specific_template(db, template_id, data) - except EmailTemplateNotFoundException as e: - raise HTTPException( - status_code=HTTP_404_NOT_FOUND, - detail=e.message, - ) - except MessagingTemplateValidationException as e: - raise HTTPException( - status_code=HTTP_400_BAD_REQUEST, - detail=e.message, - ) - - @router.get( MESSAGING_TEMPLATE_BY_ID, dependencies=[Security(verify_oauth_client, scopes=[MESSAGING_TEMPLATE_UPDATE])], diff --git a/tests/ops/api/v1/endpoints/test_messaging_endpoints.py b/tests/ops/api/v1/endpoints/test_messaging_endpoints.py index 384215b376..ac9b1cb713 100644 --- a/tests/ops/api/v1/endpoints/test_messaging_endpoints.py +++ b/tests/ops/api/v1/endpoints/test_messaging_endpoints.py @@ -2055,91 +2055,6 @@ def test_put_messaging_templates_invalid_type( } -class TestGetPropertySpecificMessagingTemplateSummary: - @pytest.fixture - def url(self) -> str: - return V1_URL_PREFIX + MESSAGING_TEMPLATES_SUMMARY - - def test_get_messaging_templates_unauthorized( - self, url, api_client: TestClient, generate_auth_header - ) -> None: - auth_header = generate_auth_header(scopes=[]) - response = api_client.get(url, headers=auth_header) - assert response.status_code == 403 - - def test_get_messaging_templates_wrong_scope( - self, url, api_client: TestClient, generate_auth_header - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_READ]) - response = api_client.get(url, headers=auth_header) - assert response.status_code == 403 - - def test_get_messaging_templates_summary_no_db_templates( - self, url, api_client: TestClient, generate_auth_header - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - response = api_client.get(url, headers=auth_header) - assert response.status_code == 200 - response_body = json.loads(response.text) - assert len(response_body["items"]) == 6 - - # Validate the response conforms to the expected model - [ - MessagingTemplateWithPropertiesSummary(**item) - for item in response_body["items"] - ] - - def test_get_all_messaging_templates_summary_some_db_templates( - self, - url, - api_client: TestClient, - generate_auth_header, - messaging_template_subject_identity_verification, - messaging_template_privacy_request_receipt, - ): - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - response = api_client.get(url, headers=auth_header) - assert response.status_code == 200 - response_body = json.loads(response.text) - assert len(response_body["items"]) == 6 - - # Validate the response conforms to the expected model - [ - MessagingTemplateWithPropertiesSummary(**item) - for item in response_body["items"] - ] - - def test_get_all_messaging_templates_summary_all_db_templates( - self, db: Session, url, api_client: TestClient, generate_auth_header, property_a - ): - content = { - "subject": "Some subject", - "body": "Some body", - } - for template_type, default_template in DEFAULT_MESSAGING_TEMPLATES.items(): - data = { - "content": content, - "properties": [{"id": property_a.id, "name": property_a.name}], - "is_enabled": True, - "type": template_type, - } - MessagingTemplate.create( - db=db, - data=data, - ) - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - response = api_client.get(url, headers=auth_header) - assert response.status_code == 200 - response_body = json.loads(response.text) - assert len(response_body["items"]) == 6 - - # Validate the response conforms to the expected model - [ - MessagingTemplateWithPropertiesSummary(**item) - for item in response_body["items"] - ] - - class TestGetMessagingTemplateDefaultByTemplateType: @pytest.fixture def url(self) -> str: @@ -2184,367 +2099,6 @@ def test_get_messaging_template_default( MessagingTemplateDefault(**resp) -class TestCreateMessagingTemplateByTemplateType: - @pytest.fixture - def url(self) -> str: - return (V1_URL_PREFIX + MESSAGING_TEMPLATES_BY_TEMPLATE_TYPE).format( - template_type=MessagingActionType.SUBJECT_IDENTITY_VERIFICATION.value - ) - - @pytest.fixture - def test_create_data(self) -> Dict[str, Any]: - return { - "content": { - "subject": "Here is your code {{code}}", - "body": "Use code {{code}} to verify your identity, you have {{minutes}} minutes!", - }, - "properties": [], - "is_enabled": False, - } - - def test_create_messaging_template_unauthorized( - self, url, api_client: TestClient, generate_auth_header, test_create_data - ) -> None: - auth_header = generate_auth_header(scopes=[]) - response = api_client.post(url, json=test_create_data, headers=auth_header) - assert response.status_code == 403 - - def test_create_messaging_template_wrong_scope( - self, url, api_client: TestClient, generate_auth_header, test_create_data - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_READ]) - response = api_client.post(url, json=test_create_data, headers=auth_header) - assert response.status_code == 403 - - def test_create_messaging_template_invalid( - self, - url, - api_client: TestClient, - generate_auth_header, - messaging_template_subject_identity_verification, - test_create_data, - property_a, - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - data = {**test_create_data, "is_enabled": True, "properties": [property_a.id]} - # Cannot create messaging template with same template type and property id as existing - response = api_client.post(url, json=data, headers=auth_header) - assert response.status_code == 400 - - def test_create_messaging_template_success( - self, - url, - db: Session, - api_client: TestClient, - generate_auth_header, - test_create_data, - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - response = api_client.post(url, json=test_create_data, headers=auth_header) - assert response.status_code == 200 - - template_with_type = MessagingTemplate.get_by( - db=db, - field="type", - value=MessagingActionType.SUBJECT_IDENTITY_VERIFICATION.value, - ) - - assert template_with_type.content == test_create_data["content"] - assert template_with_type.properties == [] - assert template_with_type.is_enabled is False - - # delete created template so that property fixture can be deleted - db.delete(template_with_type) - - def test_create_messaging_template_with_properties_success( - self, - url, - db: Session, - api_client: TestClient, - generate_auth_header, - test_create_data, - property_a, - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - data = {**test_create_data, "properties": [property_a.id]} - response = api_client.post(url, json=data, headers=auth_header) - assert response.status_code == 200 - - template_with_type = MessagingTemplate.get_by( - db=db, - field="type", - value=MessagingActionType.SUBJECT_IDENTITY_VERIFICATION.value, - ) - - assert template_with_type.content == test_create_data["content"] - assert len(template_with_type.properties) == 1 - assert template_with_type.properties[0].id == property_a.id - assert template_with_type.properties[0].name == property_a.name - assert template_with_type.is_enabled is False - - # delete created template so that property fixture can be deleted - db.delete(template_with_type) - - -class TestPatchMessagingTemplateByTemplateType: - @pytest.fixture - def url(self, messaging_template_with_property_disabled) -> str: - return (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format( - template_id=messaging_template_with_property_disabled.id - ) - - @pytest.fixture - def test_patch_data_enable(self) -> Dict[str, Any]: - return { - "is_enabled": True, - } - - def test_patch_messaging_template_unauthorized( - self, url, api_client: TestClient, generate_auth_header, test_patch_data_enable - ) -> None: - auth_header = generate_auth_header(scopes=[]) - response = api_client.patch( - url, json=test_patch_data_enable, headers=auth_header - ) - assert response.status_code == 403 - - def test_patch_messaging_template_wrong_scope( - self, url, api_client: TestClient, generate_auth_header, test_patch_data_enable - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_READ]) - response = api_client.patch( - url, json=test_patch_data_enable, headers=auth_header - ) - assert response.status_code == 403 - - def test_patch_messaging_template_invalid_id( - self, api_client: TestClient, generate_auth_header, test_patch_data_enable - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - url = (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format(template_id="invalid") - response = api_client.patch( - url, json=test_patch_data_enable, headers=auth_header - ) - assert response.status_code == 404 - - def test_patch_enable_messaging_template_invalid_data( - self, - api_client: TestClient, - generate_auth_header, - messaging_template_subject_identity_verification, - messaging_template_no_property, - property_a, - test_patch_data_enable, - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - url = (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format( - template_id=messaging_template_no_property.id - ) - - # this property is already used by the subject identity verification template - data = {**test_patch_data_enable, "properties": [property_a.id]} - - response = api_client.patch(url, json=data, headers=auth_header) - assert response.status_code == 400 - - def test_patch_enable_messaging_template_success( - self, - url, - db: Session, - api_client: TestClient, - generate_auth_header, - test_patch_data_enable, - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - response = api_client.patch( - url, json=test_patch_data_enable, headers=auth_header - ) - assert response.status_code == 200 - - template_with_type = MessagingTemplate.get_by( - db=db, - field="type", - value=MessagingActionType.SUBJECT_IDENTITY_VERIFICATION.value, - ) - - assert template_with_type.content is not None - assert len(template_with_type.properties) == 1 - assert template_with_type.is_enabled is True - - db.delete(template_with_type) - - def test_patch_enable_messaging_template_with_new_properties_success( - self, - db: Session, - api_client: TestClient, - generate_auth_header, - test_patch_data_enable, - property_a, - property_b, - ) -> None: - template_type = MessagingActionType.SUBJECT_IDENTITY_VERIFICATION.value - content = { - "subject": "Here is your code {{code}}", - "body": "Use code {{code}} to verify your identity, you have {{minutes}} minutes!", - } - data = { - "content": content, - "properties": [{"id": property_a.id, "name": property_a.name}], - "is_enabled": False, - "type": template_type, - } - messaging_template = MessagingTemplate.create( - db=db, - data=data, - ) - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - url = (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format( - template_id=messaging_template.id - ) - # replace property a with property b and enable - data = { - **test_patch_data_enable, - "is_enabled": True, - "properties": [property_b.id], - } - response = api_client.patch(url, json=data, headers=auth_header) - assert response.status_code == 200 - - db.refresh(messaging_template) - - assert messaging_template.content is not None - assert len(messaging_template.properties) == 1 - assert messaging_template.properties[0].id == property_b.id - assert messaging_template.is_enabled is True - - db.delete(messaging_template) - - def test_patch_disable_messaging_template_with_properties_success( - self, - db: Session, - api_client: TestClient, - generate_auth_header, - test_patch_data_enable, - property_a, - ) -> None: - template_type = MessagingActionType.SUBJECT_IDENTITY_VERIFICATION.value - content = { - "subject": "Here is your code {{code}}", - "body": "Use code {{code}} to verify your identity, you have {{minutes}} minutes!", - } - data = { - "content": content, - "properties": [{"id": property_a.id, "name": property_a.name}], - "is_enabled": True, - "type": template_type, - } - messaging_template = MessagingTemplate.create( - db=db, - data=data, - ) - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - url = (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format( - template_id=messaging_template.id - ) - data = { - "is_enabled": False, - } - response = api_client.patch(url, json=data, headers=auth_header) - assert response.status_code == 200 - - db.refresh(messaging_template) - - assert messaging_template.content is not None - assert len(messaging_template.properties) == 1 - assert messaging_template.is_enabled is False - - db.delete(messaging_template) - - -class TestUpdateMessagingTemplateByTemplateType: - @pytest.fixture - def url(self, messaging_template_subject_identity_verification) -> str: - return (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format( - template_id=messaging_template_subject_identity_verification.id - ) - - @pytest.fixture - def test_update_data(self) -> Dict[str, Any]: - return { - "content": { - "subject": "Hello there, here is your code: {{code}}", - "body": "Use code {{code}} to verify your identity, you have {{minutes}} minutes!", - }, - "properties": [], - "is_enabled": False, - } - - def test_update_messaging_template_unauthorized( - self, url, api_client: TestClient, generate_auth_header, test_update_data - ) -> None: - auth_header = generate_auth_header(scopes=[]) - response = api_client.put(url, json=test_update_data, headers=auth_header) - assert response.status_code == 403 - - def test_update_messaging_template_wrong_scope( - self, url, api_client: TestClient, generate_auth_header, test_update_data - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_READ]) - response = api_client.put(url, json=test_update_data, headers=auth_header) - assert response.status_code == 403 - - def test_update_messaging_template_invalid_id( - self, api_client: TestClient, generate_auth_header, test_update_data - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - url = (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format(template_id="invalid") - response = api_client.put(url, json=test_update_data, headers=auth_header) - assert response.status_code == 404 - - def test_update_messaging_template_invalid_data( - self, - api_client: TestClient, - generate_auth_header, - messaging_template_subject_identity_verification, - messaging_template_no_property, - property_a, - test_update_data, - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - url = (V1_URL_PREFIX + MESSAGING_TEMPLATE_BY_ID).format( - template_id=messaging_template_no_property.id - ) - # this property is already used by the subject identity verification template - data = {**test_update_data, "is_enabled": True, "properties": [property_a.id]} - - response = api_client.put(url, json=data, headers=auth_header) - assert response.status_code == 400 - - def test_update_messaging_template_success( - self, - url, - db: Session, - api_client: TestClient, - generate_auth_header, - test_update_data, - ) -> None: - auth_header = generate_auth_header(scopes=[MESSAGING_TEMPLATE_UPDATE]) - response = api_client.put(url, json=test_update_data, headers=auth_header) - assert response.status_code == 200 - - template_with_type = MessagingTemplate.get_by( - db=db, - field="type", - value=MessagingActionType.SUBJECT_IDENTITY_VERIFICATION.value, - ) - - assert template_with_type.content == test_update_data["content"] - assert template_with_type.properties == [] - assert template_with_type.is_enabled is False - - db.delete(template_with_type) - - class TestGetMessagingTemplateById: @pytest.fixture def url(self, messaging_template_subject_identity_verification) -> str: