Skip to content

Commit

Permalink
Bump downrev.
Browse files Browse the repository at this point in the history
- Move new get_or_create_fides_user_device_id_provided_identity and get_fides_user_device_id_provided_identity into a consent util.
- Update copy paste error in get privacy preferences docstring.
  • Loading branch information
pattisdr committed Apr 25, 2023
1 parent f14098a commit e69e85e
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""save privacy preferences on device id
Revision ID: 451684a726a5
Revises: 3842d1acac5f
Revises: 48d9caacebd4
Create Date: 2023-04-23 16:06:19.788074
"""
Expand All @@ -11,7 +11,7 @@

# revision identifiers, used by Alembic.
revision = "451684a726a5"
down_revision = "3842d1acac5f"
down_revision = "48d9caacebd4"
branch_labels = None
depends_on = None

Expand Down
57 changes: 0 additions & 57 deletions src/fides/api/ops/api/v1/endpoints/consent_request_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,63 +462,6 @@ def set_consent_preferences(
return consent_preferences


def _get_fides_user_device_id_provided_identity(
db: Session, fides_user_device_id: Optional[str]
) -> Optional[ProvidedIdentity]:
"""Look up a fides user device id that is not attached to a privacy request if it exists
There can be many fides user device ids attached to privacy requests, but we should try to keep them
unique for consent requests.
"""
if not fides_user_device_id:
return None

return ProvidedIdentity.filter(
db=db,
conditions=(
(ProvidedIdentity.field_name == ProvidedIdentityType.fides_user_device_id)
& (
ProvidedIdentity.hashed_value
== ProvidedIdentity.hash_value(fides_user_device_id)
)
& (ProvidedIdentity.privacy_request_id.is_(None))
),
).first()


def _get_or_create_fides_user_device_id_provided_identity(
db: Session,
identity_data: Identity,
) -> ProvidedIdentity:
"""Gets an existing fides user device id provided identity or creates one if it doesn't exist.
Raises an error if no fides user device id is supplied.
"""
if not identity_data.fides_user_device_id:
raise HTTPException(
HTTP_422_UNPROCESSABLE_ENTITY,
detail="Fides user device id not found in identity data",
)

identity = _get_fides_user_device_id_provided_identity(
db, identity_data.fides_user_device_id
)

if not identity:
identity = ProvidedIdentity.create(
db,
data={
"privacy_request_id": None,
"field_name": ProvidedIdentityType.fides_user_device_id.value,
"hashed_value": ProvidedIdentity.hash_value(
identity_data.fides_user_device_id
),
"encrypted_value": {"value": identity_data.fides_user_device_id},
},
)

return identity # type: ignore[return-value]


def _get_or_create_provided_identity(
db: Session,
identity_data: Identity,
Expand Down
25 changes: 11 additions & 14 deletions src/fides/api/ops/api/v1/endpoints/privacy_preference_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
from fides.api.ops.api.deps import get_db
from fides.api.ops.api.v1.endpoints.consent_request_endpoints import (
_get_consent_request_and_provided_identity,
_get_fides_user_device_id_provided_identity,
_get_or_create_fides_user_device_id_provided_identity,
)
from fides.api.ops.api.v1.endpoints.privacy_request_endpoints import (
create_privacy_request_func,
Expand Down Expand Up @@ -66,6 +64,10 @@
)
from fides.api.ops.schemas.redis_cache import Identity
from fides.api.ops.util.api_router import APIRouter
from fides.api.ops.util.consent_util import (
get_fides_user_device_id_provided_identity,
get_or_create_fides_user_device_id_provided_identity,
)
from fides.api.ops.util.oauth_util import verify_oauth_client
from fides.core.config import CONFIG
from fides.core.config.config_proxy import ConfigProxy
Expand Down Expand Up @@ -190,7 +192,7 @@ def save_privacy_preferences_with_verified_identity(

try:
fides_user_provided_identity = (
_get_or_create_fides_user_device_id_provided_identity(
get_or_create_fides_user_device_id_provided_identity(
db=db, identity_data=data.browser_identity
)
)
Expand Down Expand Up @@ -330,15 +332,11 @@ def get_privacy_preferences_by_device_id(
db: Session = Depends(get_db),
params: Params = Depends(),
) -> AbstractPage[CurrentPrivacyPreference]:
"""Saves privacy preferences with respect to a fides user device id.
Creates historical records for these preferences for record keeping, and also updates current preferences.
Creates a privacy request to propagate preferences to third party systems.
"""
"""Retrieves privacy preferences with respect to a fides user device id."""
verify_address(request)
fides_user_provided_identity: Optional[
ProvidedIdentity
] = _get_fides_user_device_id_provided_identity(
] = get_fides_user_device_id_provided_identity(
db=db, fides_user_device_id=fides_user_device_id
)

Expand Down Expand Up @@ -381,10 +379,8 @@ def save_privacy_preferences(
verify_privacy_notice_and_historical_records(db=db, data=data)
verify_address(request)

fides_user_provided_identity = (
_get_or_create_fides_user_device_id_provided_identity(
db=db, identity_data=data.browser_identity
)
fides_user_provided_identity = get_or_create_fides_user_device_id_provided_identity(
db=db, identity_data=data.browser_identity
)

logger.info("Saving privacy preferences with respect to fides user device id")
Expand Down Expand Up @@ -453,7 +449,8 @@ def get_historical_consent_report(
db.query(
PrivacyPreferenceHistory.id,
PrivacyRequest.id.label("privacy_request_id"),
PrivacyPreferenceHistory.email.label("user_id"),
PrivacyPreferenceHistory.email.label("email"),
PrivacyPreferenceHistory.phone_number.label("phone_number"),
PrivacyPreferenceHistory.fides_user_device.label("fides_user_device_id"),
PrivacyPreferenceHistory.secondary_user_ids,
PrivacyPreferenceHistory.created_at.label("request_timestamp"),
Expand Down
3 changes: 2 additions & 1 deletion src/fides/api/ops/schemas/privacy_preference.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class ConsentReportingSchema(BaseSchema):
privacy_request_id: Optional[str] = Field(
title="The Privacy Request id created to propagate preferences"
)
user_id: Optional[str] = Field(title="Email if provided")
email: Optional[str] = Field(title="Email if applicable")
phone_number: Optional[str] = Field(title="Phone number if applicable")
fides_user_device_id: Optional[str] = Field(
title="Fides user device id if applicable"
)
Expand Down
67 changes: 66 additions & 1 deletion src/fides/api/ops/util/consent_util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import Any, Dict, List, Optional, Tuple

from fastapi import HTTPException
from sqlalchemy.orm import Session
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY

from fides.api.ctl.sql_models import System # type: ignore[attr-defined]
from fides.api.ops.models.connectionconfig import ConnectionConfig
Expand All @@ -9,7 +11,13 @@
PrivacyPreferenceHistory,
UserConsentPreference,
)
from fides.api.ops.models.privacy_request import ExecutionLogStatus, PrivacyRequest
from fides.api.ops.models.privacy_request import (
ExecutionLogStatus,
PrivacyRequest,
ProvidedIdentity,
ProvidedIdentityType,
)
from fides.api.ops.schemas.redis_cache import Identity


def filter_privacy_preferences_for_propagation(
Expand Down Expand Up @@ -165,3 +173,60 @@ def add_errored_system_status_for_consent_reporting(
connection_config.system_key,
ExecutionLogStatus.error,
)


def get_fides_user_device_id_provided_identity(
db: Session, fides_user_device_id: Optional[str]
) -> Optional[ProvidedIdentity]:
"""Look up a fides user device id that is not attached to a privacy request if it exists
There can be many fides user device ids attached to privacy requests, but we should try to keep them
unique for consent requests.
"""
if not fides_user_device_id:
return None

return ProvidedIdentity.filter(
db=db,
conditions=(
(ProvidedIdentity.field_name == ProvidedIdentityType.fides_user_device_id)
& (
ProvidedIdentity.hashed_value
== ProvidedIdentity.hash_value(fides_user_device_id)
)
& (ProvidedIdentity.privacy_request_id.is_(None))
),
).first()


def get_or_create_fides_user_device_id_provided_identity(
db: Session,
identity_data: Identity,
) -> ProvidedIdentity:
"""Gets an existing fides user device id provided identity or creates one if it doesn't exist.
Raises an error if no fides user device id is supplied.
"""
if not identity_data.fides_user_device_id:
raise HTTPException(
HTTP_422_UNPROCESSABLE_ENTITY,
detail="Fides user device id not found in identity data",
)

identity = get_fides_user_device_id_provided_identity(
db, identity_data.fides_user_device_id
)

if not identity:
identity = ProvidedIdentity.create(
db,
data={
"privacy_request_id": None,
"field_name": ProvidedIdentityType.fides_user_device_id.value,
"hashed_value": ProvidedIdentity.hash_value(
identity_data.fides_user_device_id
),
"encrypted_value": {"value": identity_data.fides_user_device_id},
},
)

return identity # type: ignore[return-value]
1 change: 0 additions & 1 deletion tests/ctl/core/test_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ def delete_server_systems(test_config: FidesConfig, systems: List[System]) -> No


def test_get_system_data_uses(db, system) -> None:

assert sql_System.get_data_uses([system]) == {"advertising"}

system.privacy_declarations[0].update(
Expand Down
24 changes: 1 addition & 23 deletions tests/ops/api/v1/endpoints/test_consent_request_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
import pytest
from requests import Session

from fides.api.ops.api.v1.endpoints.consent_request_endpoints import (
_get_fides_user_device_id_provided_identity,
)
from fides.api.ops.api.v1.scope_registry import CONNECTION_READ, CONSENT_READ
from fides.api.ops.api.v1.urn_registry import (
CONSENT_REQUEST,
Expand All @@ -27,6 +24,7 @@
ProvidedIdentity,
)
from fides.api.ops.schemas.messaging.messaging import MessagingServiceType
from fides.api.ops.util.consent_util import get_fides_user_device_id_provided_identity
from fides.core.config import CONFIG


Expand Down Expand Up @@ -1168,23 +1166,3 @@ def test_get_consent_preferences(
},
]
assert response.json()["consent"] == expected_consent_data


class TestGetFidesUserProvidedIdentity:
def test_no_identifier_supplied(self, db):
provided_identity = _get_fides_user_device_id_provided_identity(db, None)
assert provided_identity is None

def test_no_provided_identifier_exists(self, db):
provided_identity = _get_fides_user_device_id_provided_identity(
db, "fides_user_device_id"
)
assert provided_identity is None

def test_get_fides_user_device_id_provided_identity(
self, db, fides_user_provided_identity
):
provided_identity = _get_fides_user_device_id_provided_identity(
db, "FGHIJ_TEST_FIDES"
)
assert provided_identity == fides_user_provided_identity
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
from starlette.status import HTTP_200_OK, HTTP_403_FORBIDDEN
from starlette.testclient import TestClient

from fides.api.ops.api.v1.endpoints.consent_request_endpoints import (
_get_or_create_fides_user_device_id_provided_identity,
)
from fides.api.ops.api.v1.scope_registry import (
CONSENT_READ,
CURRENT_PRIVACY_PREFERENCE_READ,
Expand Down Expand Up @@ -1172,7 +1169,9 @@ def test_get_historical_preferences(
response_body["privacy_request_id"]
== privacy_request_with_consent_policy.id
)
assert response_body["user_id"] == "[email protected]"
assert response_body["email"] == "[email protected]"
assert response_body["phone_number"] is None
assert response_body["fides_user_device_id"] is None
assert response_body["secondary_user_ids"] == {
"ljt_readerID": "preference_history_test"
}
Expand Down
21 changes: 21 additions & 0 deletions tests/ops/util/test_consent_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
add_complete_system_status_for_consent_reporting,
add_errored_system_status_for_consent_reporting,
cache_initial_status_and_identities_for_consent_reporting,
get_fides_user_device_id_provided_identity,
should_opt_in_to_service,
)

Expand Down Expand Up @@ -436,3 +437,23 @@ def test_add_error_system_status_for_consent_reporting(
connection_config.name: "skipped"
}
assert privacy_preference_history.secondary_user_ids is None


class TestGetFidesUserProvidedIdentity:
def test_no_identifier_supplied(self, db):
provided_identity = get_fides_user_device_id_provided_identity(db, None)
assert provided_identity is None

def test_no_provided_identifier_exists(self, db):
provided_identity = get_fides_user_device_id_provided_identity(
db, "fides_user_device_id"
)
assert provided_identity is None

def test_get_fides_user_device_id_provided_identity(
self, db, fides_user_provided_identity
):
provided_identity = get_fides_user_device_id_provided_identity(
db, "FGHIJ_TEST_FIDES"
)
assert provided_identity == fides_user_provided_identity

0 comments on commit e69e85e

Please sign in to comment.