Skip to content

Commit

Permalink
Support for consent management report (#4452)
Browse files Browse the repository at this point in the history
  • Loading branch information
galvana authored Dec 1, 2023
1 parent 0f06766 commit f008dcf
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ The types of changes are:

## [Unreleased](https://github.com/ethyca/fides/compare/2.25.0...main)

### Added
- New purposes endpoint and indices to improve system lookups [#4452](https://github.com/ethyca/fides/pull/4452)

### Fixed
- Fix type errors when TCF vendors have no dataDeclaration [#4465](https://github.com/ethyca/fides/pull/4465)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""add indexes to ctl_systems and privacydeclaration
Revision ID: 7f7c2b098f5d
Revises: 1af6950f4625
Create Date: 2023-11-21 18:52:34.508076
"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "7f7c2b098f5d"
down_revision = "1af6950f4625"
branch_labels = None
depends_on = None


def upgrade():
op.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;")
op.create_index(
"ix_ctl_systems_name",
"ctl_systems",
[sa.text("name gin_trgm_ops")],
postgresql_using="gin",
)


def downgrade():
op.drop_index("ix_ctl_systems_name", table_name="ctl_systems")
op.execute("DROP EXTENSION IF EXISTS pg_trgm;")
2 changes: 2 additions & 0 deletions src/fides/api/api/v1/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
privacy_notice_endpoints,
privacy_preference_endpoints,
privacy_request_endpoints,
purpose_endpoints,
registration_endpoints,
saas_config_endpoints,
served_notice_endpoints,
Expand Down Expand Up @@ -51,3 +52,4 @@
api_router.include_router(manual_webhook_endpoints.router)
api_router.include_router(registration_endpoints.router)
api_router.include_router(served_notice_endpoints.router)
api_router.include_router(purpose_endpoints.router)
34 changes: 34 additions & 0 deletions src/fides/api/api/v1/endpoints/purpose_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from fastapi import Depends, Security
from fideslang.gvl import MAPPED_PURPOSES, MAPPED_SPECIAL_PURPOSES
from sqlalchemy.orm import Session
from starlette.status import HTTP_200_OK

from fides.api.api import deps
from fides.api.oauth.utils import verify_oauth_client
from fides.api.schemas.tcf import PurposesResponse
from fides.api.util.api_router import APIRouter
from fides.common.api.v1 import urn_registry as urls

router = APIRouter(tags=["Purposes"], prefix=urls.V1_URL_PREFIX)


@router.get(
"/purposes",
dependencies=[Security(verify_oauth_client)],
status_code=HTTP_200_OK,
response_model=PurposesResponse,
)
def get_purposes(
db: Session = Depends(deps.get_db),
) -> PurposesResponse:
"""
Return a map of purpose and special purpose IDs to mapped purposes which include data uses.
"""

purposes = {}
special_purposes = {}
for purpose in MAPPED_PURPOSES.values():
purposes[purpose.id] = purpose
for special_purpose in MAPPED_SPECIAL_PURPOSES.values():
special_purposes[special_purpose.id] = special_purpose
return PurposesResponse(purposes=purposes, special_purposes=special_purposes)
7 changes: 6 additions & 1 deletion src/fides/api/schemas/tcf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
MAPPED_SPECIAL_PURPOSES,
)
from fideslang.gvl.models import Feature, MappedPurpose
from pydantic import AnyUrl, root_validator, validator
from pydantic import AnyUrl, BaseModel, root_validator, validator

from fides.api.models.privacy_notice import UserConsentPreference
from fides.api.schemas.base_class import FidesSchema
Expand Down Expand Up @@ -230,3 +230,8 @@ def validate_special_feature_id(cls, value: int) -> int:
f"Cannot save preferences against invalid special feature id: '{value}'"
)
return value


class PurposesResponse(BaseModel):
purposes: Dict[str, MappedPurpose]
special_purposes: Dict[str, MappedPurpose]
3 changes: 3 additions & 0 deletions src/fides/common/api/v1/urn_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
"/privacy-request/transfer/{privacy_request_id}/{rule_key}"
)

# Purpose URLs
PURPOSES = "/purposes"


# Identity Verification URLs
ID_VERIFICATION_CONFIG = "/id-verification/config"
Expand Down
25 changes: 25 additions & 0 deletions tests/ops/api/v1/endpoints/test_purpose_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import pytest
from starlette.status import HTTP_200_OK, HTTP_401_UNAUTHORIZED

from fides.common.api.v1.urn_registry import PURPOSES, V1_URL_PREFIX


class TestGetPurposes:
@pytest.fixture(scope="function")
def url(self) -> str:
return V1_URL_PREFIX + PURPOSES

def test_get_purposes_unauthenticated(self, url, api_client):
response = api_client.get(url)
assert response.status_code == HTTP_401_UNAUTHORIZED

def test_get_purposes(self, url, api_client, generate_auth_header):
auth_header = generate_auth_header([])
response = api_client.get(url, headers=auth_header)
assert response.status_code == HTTP_200_OK

data = response.json()
assert "purposes" in data
assert "special_purposes" in data
assert len(data["purposes"]) == 11
assert len(data["special_purposes"]) == 2

0 comments on commit f008dcf

Please sign in to comment.