diff --git a/README.pod b/README.pod index 6a1a83d..2f2b099 100644 --- a/README.pod +++ b/README.pod @@ -325,6 +325,13 @@ It true, there is a publisher restriction of certain type, for a given purpose i # with restriction type 0 'Purpose Flatly Not Allowed by Publisher' my $ok = $instance->check_publisher_restriction(1, 0, 284); +or + + my $ok = $instance->check_publisher_restriction( + purpose_id => 1, + restriction_type => 0, + vendor_id => 284); + Version 2.0 of the Framework introduced the ability for publishers to signal restrictions on how vendors may process personal data. Restrictions can be of two types: =over @@ -357,6 +364,10 @@ For the avoidance of doubt: In case a vendor has declared flexibility for a purpose and there is no legal basis restriction signal it must always apply the default legal basis under which the purpose was registered aside from being registered as flexible. That means if a vendor declared a purpose as legitimate interest and also declared that purpose as flexible it may not apply a "consent" signal without a legal basis restriction signal to require consent. +=head2 publisher_restrictions + +Similar to L but return an hashref of purpose => restriction type for a given vendor (if any). + =head2 publisher_tc If the consent string has a C section, we will decode this section as an instance of L. diff --git a/lib/GDPR/IAB/TCFv2.pm b/lib/GDPR/IAB/TCFv2.pm index 5e73989..51ab53d 100644 --- a/lib/GDPR/IAB/TCFv2.pm +++ b/lib/GDPR/IAB/TCFv2.pm @@ -351,6 +351,12 @@ sub check_publisher_restriction { ->check_restriction( $purpose_id, $restriction_type, $vendor_id ); } +sub publisher_restrictions { + my ( $self, $vendor_id ) = @_; + + return $self->{publisher}->restrictions($vendor_id); +} + sub publisher_tc { my $self = shift; @@ -1010,6 +1016,10 @@ For the avoidance of doubt: In case a vendor has declared flexibility for a purpose and there is no legal basis restriction signal it must always apply the default legal basis under which the purpose was registered aside from being registered as flexible. That means if a vendor declared a purpose as legitimate interest and also declared that purpose as flexible it may not apply a "consent" signal without a legal basis restriction signal to require consent. +=head2 publisher_restrictions + +Similar to L but return an hashref of purpose => restriction type for a given vendor (if any). + =head2 publisher_tc If the consent string has a C section, we will decode this section as an instance of L. diff --git a/lib/GDPR/IAB/TCFv2/Publisher.pm b/lib/GDPR/IAB/TCFv2/Publisher.pm index 136f0e1..4119478 100644 --- a/lib/GDPR/IAB/TCFv2/Publisher.pm +++ b/lib/GDPR/IAB/TCFv2/Publisher.pm @@ -51,10 +51,16 @@ sub Parse { } sub check_restriction { - my ( $self, $purpose_id, $restrict_type, $vendor ) = @_; + my ( $self, $purpose_id, $restriction_type, $vendor_id ) = @_; return $self->{restrictions} - ->check_restriction( $purpose_id, $restrict_type, $vendor ); + ->check_restriction( $purpose_id, $restriction_type, $vendor_id ); +} + +sub restrictions { + my ( $self, $vendor_id ) = @_; + + return $self->{restrictions}->restrictions($vendor_id); } sub publisher_tc { @@ -95,7 +101,7 @@ Combines the creation of L and L { json => ... }, ); - say "there is publisher restriction on purpose id 1, type 0 on vendor 284" + say "there is publisher restriction on purpose id 1, type 0 on vendor_id 284" if $publisher->check_restriction(1, 0, 284); =head1 CONSTRUCTOR @@ -126,12 +132,21 @@ Key C is the L options (includes the C field to =head2 check_restriction -Return true for a given combination of purpose id, restriction type and vendor +Return true for a given combination of purpose id, restriction type and vendor_id my $purpose_id = 1; my $restriction_type = 0; - my $vendor = 284; - $ok = $range->check_restriction($purpose_id, $restriction_type, $vendor); + my $vendor_id = 284; + $ok = $range->check_restriction($purpose_id, $restriction_type, $vendor_id); + +=head2 restrictions + +Return a map of purpose id => restriction type for a given vendor id + +Example, by parsing the consent C we can generate this. + + my $restrictions = $range->restrictions(32); + # returns { 7 => 1 } =head2 publisher_tc @@ -155,7 +170,7 @@ Returns a hashref with the following format: # 0 - Not Allowed # 1 - Require Consent # 2 - Require Legitimate Interest - '[vendor id]' => 1, + '[vendor_id id]' => 1, }, } } diff --git a/lib/GDPR/IAB/TCFv2/PublisherRestrictions.pm b/lib/GDPR/IAB/TCFv2/PublisherRestrictions.pm index bdfd888..220f6c3 100644 --- a/lib/GDPR/IAB/TCFv2/PublisherRestrictions.pm +++ b/lib/GDPR/IAB/TCFv2/PublisherRestrictions.pm @@ -66,6 +66,26 @@ sub Parse { return $self; } +sub restrictions { + my ( $self, $vendor_id ) = @_; + + my %restrictions; + + foreach my $purpose_id ( keys %{ $self->{restrictions} } ) { + foreach my $restriction_type ( + keys %{ $self->{restrictions}->{$purpose_id} } ) + { + if ( $self->{restrictions}->{$purpose_id}->{$restriction_type} + ->contains($vendor_id) ) + { + $restrictions{$purpose_id} = $restriction_type; + } + } + } + + return \%restrictions; +} + sub check_restriction { my $self = shift; @@ -155,8 +175,17 @@ Return true for a given combination of purpose id, restriction type and vendor my $purpose_id = 1; my $restriction_type = 0; - my $vendor = 284; - my $ok = $range->check_restriction($purpose_id, $restriction_type, $vendor); + my $vendor_id = 284; + my $ok = $range->check_restriction($purpose_id, $restriction_type, $vendor_id); + +=head2 restrictions + +Return a map of purpose id => restriction type for a given vendor id + +Example, by parsing the consent C we can generate this. + + my $restrictions = $range->restrictions(32); + # returns { 7 => 1 } =head2 TO_JSON diff --git a/t/00-load.t b/t/00-load.t index 999318c..d578a3f 100644 --- a/t/00-load.t +++ b/t/00-load.t @@ -42,9 +42,9 @@ subtest "check interfaces" => sub { @role_decoder_methods, qw; can_ok 'GDPR::IAB::TCFv2::PublisherRestrictions', @role_base_methods, - qw; + qw; can_ok 'GDPR::IAB::TCFv2::Publisher', @role_base_methods, - qw; + qw; can_ok 'GDPR::IAB::TCFv2::PublisherTC', @role_base_methods, qw sub { ok !$consent->check_publisher_restriction( 1, 0, 284 ), "should have no publisher restriction to vendor 284 regarding purpose id 1 of type 0 'Purpose Flatly Not Allowed by Publisher' when called with positional parameters"; - ok !$consent->check_publisher_restriction( purpose_id => 1, - restriction_type => 0, vendor_id => 284 ), + ok !$consent->check_publisher_restriction( + purpose_id => 1, + restriction_type => 0, vendor_id => 284 + ), "should have no publisher restriction to vendor 284 regarding purpose id 1 of type 0 'Purpose Flatly Not Allowed by Publisher' when called with named parameters"; + my $restrictions = $consent->publisher_restrictions(284); + is_deeply $restrictions, {}, + "should return the restriction purpose id => restriction type map"; + my $publisher_tc = $consent->publisher_tc; ok !defined($publisher_tc), "should not return publisher_tc"; @@ -442,6 +448,10 @@ subtest "range" => sub { ok !$consent->check_publisher_restriction( 1, 0, 284 ), "should have no publisher restriction to vendor 284 regarding purpose id 1 of type 0 'Purpose Flatly Not Allowed by Publisher'"; + my $restrictions = $consent->publisher_restrictions(284); + is_deeply $restrictions, {}, + "should return the restriction purpose id => restriction type map"; + my $publisher_tc = $consent->publisher_tc; ok !defined($publisher_tc), "should not return publisher_tc"; @@ -503,6 +513,10 @@ subtest "range" => sub { ok !$consent->check_publisher_restriction( 1, 0, 284 ), "should have no publisher restriction to vendor 284 regarding purpose id 1 of type 0 'Purpose Flatly Not Allowed by Publisher'"; + my $restrictions = $consent->publisher_restrictions(284); + is_deeply $restrictions, {}, + "should return the restriction purpose id => restriction type map"; + done_testing; }; done_testing; @@ -533,6 +547,14 @@ subtest "check publisher restriction" => sub { ok !$consent->check_publisher_restriction( 5, 1, 32 ), "must have publisher restriction to vendor 32 regarding purpose id 5 of type 1 'Require Consent'"; + my $restrictions = $consent->publisher_restrictions(284); + is_deeply $restrictions, {}, + "should return the restriction purpose id => restriction type map"; + + $restrictions = $consent->publisher_restrictions(32); + is_deeply $restrictions, { 7 => 1 }, + "should return the restriction purpose id => restriction type map"; + done_testing; }; @@ -573,6 +595,15 @@ subtest "check publisher restriction" => sub { ok $consent->check_publisher_restriction( 2, 1, 32 ); ok !$consent->check_publisher_restriction( 2, 1, 42 ); + my $restrictions = $consent->publisher_restrictions(284); + is_deeply $restrictions, {}, + "should return the restriction purpose id => restriction type map"; + + $restrictions = $consent->publisher_restrictions(32); + is_deeply $restrictions, { 1 => 0, 2 => 0, 7 => 0, 10 => 0 }, + "should return the restriction purpose id => restriction type map"; + + done_testing; }; @@ -592,6 +623,10 @@ subtest "check publisher restriction" => sub { ok !$consent->check_publisher_restriction( 1, 0, 284 ), "should have no publisher restriction to vendor 284 regarding purpose id 1 of type 0 'Purpose Flatly Not Allowed by Publisher'"; + my $restrictions = $consent->publisher_restrictions(284); + is_deeply $restrictions, {}, + "should return the restriction purpose id => restriction type map"; + done_testing; };