diff --git a/CHANGELOG.md b/CHANGELOG.md index 863a912c0..f91cb6a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ The types of changes are: * Added generic request sorting button [#1320](https://github.com/ethyca/fidesops/pull/1320) * Adds ability to send email notification upon privacy request review [#1306](https://github.com/ethyca/fidesops/pull/1306) * Manual webhook test functionality [#1323](https://github.com/ethyca/fidesops/pull/1323/) +* Added change request table [#1340](https://github.com/ethyca/fidesops/pull/1340) ### Changed diff --git a/src/fidesops/ops/migrations/versions/021d288d0ce3_add_consent_request.py b/src/fidesops/ops/migrations/versions/021d288d0ce3_add_consent_request.py new file mode 100644 index 000000000..1efb343fc --- /dev/null +++ b/src/fidesops/ops/migrations/versions/021d288d0ce3_add_consent_request.py @@ -0,0 +1,58 @@ +"""Add consent request + +Revision ID: 021d288d0ce3 +Revises: a0e6feb5bdc8 +Create Date: 2022-09-17 01:26:43.187484 + +""" +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = "021d288d0ce3" +down_revision = "a0e6feb5bdc8" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "consentrequest", + sa.Column("id", sa.String(length=255), nullable=False), + sa.Column( + "created_at", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=True, + ), + sa.Column( + "updated_at", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=True, + ), + sa.Column("provided_identity_id", sa.String(), nullable=False), + sa.ForeignKeyConstraint( + ["provided_identity_id"], + ["providedidentity.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_index( + op.f("ix_consentrequest_id"), "consentrequest", ["id"], unique=False + ) + op.alter_column( + "consent", "provided_identity_id", existing_type=sa.VARCHAR(), nullable=False + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column( + "consent", "provided_identity_id", existing_type=sa.VARCHAR(), nullable=True + ) + op.drop_index(op.f("ix_consentrequest_id"), table_name="consentrequest") + op.drop_table("consentrequest") + # ### end Alembic commands ### diff --git a/src/fidesops/ops/models/privacy_request.py b/src/fidesops/ops/models/privacy_request.py index 9e269e678..d3ffb3c0b 100644 --- a/src/fidesops/ops/models/privacy_request.py +++ b/src/fidesops/ops/models/privacy_request.py @@ -760,6 +760,11 @@ class ProvidedIdentity(Base): # pylint: disable=R0904 consent = relationship( "Consent", back_populates="provided_identity", cascade="delete, delete-orphan" ) + consent_request = relationship( + "ConsentRequest", + back_populates="provided_identity", + cascade="delete, delete-orphan", + ) @classmethod def hash_value( @@ -779,7 +784,9 @@ def hash_value( class Consent(Base): """The DB ORM model for Consent.""" - provided_identity_id = Column(String, ForeignKey(ProvidedIdentity.id)) + provided_identity_id = Column( + String, ForeignKey(ProvidedIdentity.id), nullable=False + ) data_use = Column(String, nullable=False, unique=True) data_use_description = Column(String) opt_in = Column(Boolean, nullable=False) @@ -787,6 +794,19 @@ class Consent(Base): provided_identity = relationship(ProvidedIdentity, back_populates="consent") +class ConsentRequest(Base): + """Tracks consent requests.""" + + provided_identity_id = Column( + String, ForeignKey(ProvidedIdentity.id), nullable=False + ) + + provided_identity = relationship( + ProvidedIdentity, + back_populates="consent_request", + ) + + # Unique text to separate a step from a collection address, so we can store two values in one. PAUSED_SEPARATOR = "__fidesops_paused_sep__" diff --git a/tests/ops/models/test_privacy_request.py b/tests/ops/models/test_privacy_request.py index 8b5f33b4b..38febb907 100644 --- a/tests/ops/models/test_privacy_request.py +++ b/tests/ops/models/test_privacy_request.py @@ -17,6 +17,7 @@ from fidesops.ops.models.privacy_request import ( CheckpointActionRequired, Consent, + ConsentRequest, PrivacyRequest, PrivacyRequestStatus, ProvidedIdentity, @@ -701,3 +702,30 @@ def test_consent(db): assert Consent.get(db, object_id=consent_1.id) is None assert Consent.get(db, object_id=consent_2.id) is None + + +def test_consent_request(db): + provided_identity_data = { + "privacy_request_id": None, + "field_name": "email", + "encrypted_value": {"value": "test@email.com"}, + } + provided_identity = ProvidedIdentity.create(db, data=provided_identity_data) + + consent_request_1 = { + "provided_identity_id": provided_identity.id, + } + consent_1 = ConsentRequest.create(db, data=consent_request_1) + + consent_request_2 = { + "provided_identity_id": provided_identity.id, + } + consent_2 = ConsentRequest.create(db, data=consent_request_2) + + assert consent_1.provided_identity_id in provided_identity.id + assert consent_2.provided_identity_id in provided_identity.id + + provided_identity.delete(db) + + assert Consent.get(db, object_id=consent_1.id) is None + assert Consent.get(db, object_id=consent_2.id) is None