-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
202411 consentratio lp 135 #495
base: develop
Are you sure you want to change the base?
Changes from 5 commits
1946ebf
2f42aab
b96db34
3106319
35113d9
d41ba3d
772d573
6679bdb
721ea93
a2d8721
3e1a290
b5362f9
0bbe4e2
081f9ec
66394cb
e0c965d
e799c66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
enable: '1' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Essex Co Co cookie consent statistics. | ||
|
||
This module hooks into the events thown by the EU Cookie Compliance module. | ||
|
||
Whenever consent is set, this module takes a simplified value of choice: i.e. | ||
granted or denied, and sends it to an endpoint. | ||
|
||
The endpoint controller writes the time and value to a custom table. | ||
|
||
An administrator can access a simple aggregate report of choices. It calculates | ||
the percentage of grants out of the total number of records. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Schema for the configuration files of the ECC Cookie Consent Tracker module. | ||
ecc_cct.settings: | ||
type: config_object | ||
label: 'ECC Cookie Consent Tracker settings' | ||
mapping: | ||
enable: | ||
type: string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not boolean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The exact why is lost in the mists of history, but I'm guessing it's an artifact of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generate may be quick but it's no guarantee of good code. |
||
label: 'enable' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
name: 'ECC Cookie Consent Tracker' | ||
type: module | ||
description: 'Tracks cookie consent choices and stores them for reporting.' | ||
package: Custom | ||
core_version_requirement: ^10 || ^11 | ||
dependencies: | ||
- eu_cookie_consent:eu_cookie_compliance |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Install, update and uninstall functions for the ECC Cookie Consent Tracker module. | ||
*/ | ||
|
||
/** | ||
* Implements hook_schema(). | ||
*/ | ||
function ecc_cct_schema() { | ||
Polynya marked this conversation as resolved.
Show resolved
Hide resolved
|
||
$schema['ecc_cct_data'] = [ | ||
'description' => 'Contains custom cookie consent data.', | ||
'fields' => [ | ||
'id' => [ | ||
'type' => 'serial', | ||
'not null' => TRUE, | ||
'description' => 'Primary Key: Unique record ID.', | ||
], | ||
'choice' => [ | ||
'type' => 'int', | ||
'unsigned' => TRUE, | ||
'not null' => TRUE, | ||
'size' => 'small', | ||
'default' => 0, | ||
'description' => 'The value of the choice.', | ||
], | ||
'timestamp' => [ | ||
'type' => 'int', | ||
'unsigned' => TRUE, | ||
'not null' => TRUE, | ||
'size' => 'big', | ||
'default' => 0, | ||
'description' => 'Date of choice.', | ||
], | ||
], | ||
'primary key' => ['id'], | ||
]; | ||
|
||
return $schema; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Custom library for general purposes. | ||
ecc_cct: | ||
js: | ||
js/ecc_cct.js: {} | ||
dependencies: | ||
- core/drupalSettings |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Simple link. | ||
ecc_cct.report: | ||
title: Consent Statistics | ||
description: Consent Statistics. | ||
menu_name: administration | ||
route_name: ecc_cct.report | ||
parent: system.admin_reports | ||
weight: 10 | ||
|
||
ecc_cct.settings: | ||
title: Essex Cookie Consent Tracker | ||
parent: system.admin_config_system | ||
route_name: ecc_cct.settings | ||
weight: 10 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
use \Drupal\Core\Form\FormStateInterface; | ||
|
||
/** | ||
* @file | ||
* Primary module hooks for ECC Cookie Consent Tracker module. | ||
*/ | ||
|
||
/** | ||
* Implements hook_preprocess_html(). | ||
*/ | ||
function ecc_cct_preprocess_html(&$vars) { | ||
if ($vars['root_path'] !== 'admin') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be better to exclude the same paths as EU Cookie Compliance There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changes as follows:
|
||
$vars['#attached']['library'][] = 'ecc_cct/ecc_cct'; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
ecc_cct.log: | ||
path: '/ecc-cct/js/log/{choice}' | ||
defaults: | ||
_title: 'Content Log' | ||
_controller: '\Drupal\ecc_cct\Controller\ConsentLog:log' | ||
requirements: | ||
_permission: 'access content' | ||
choice: '\d+' # Restricts 'choice' to be numeric only | ||
|
||
ecc_cct.report: | ||
path: 'admin/reports/consent' | ||
defaults: | ||
_title: 'Consent Statistics' | ||
_controller: '\Drupal\ecc_cct\Controller\EccCctController:build' | ||
requirements: | ||
_permission: 'access site reports' | ||
|
||
ecc_cct.settings: | ||
path: '/admin/config/system/cookie-consent-tracker' | ||
defaults: | ||
_title: 'Cookie Consent Tracker' | ||
_form: 'Drupal\ecc_cct\Form\SettingsForm' | ||
requirements: | ||
_permission: 'administer site configuration' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
|
||
|
||
(function ($, Drupal, drupalSettings, cookies) { | ||
|
||
Drupal.behaviors.eccCCT = { | ||
attach: function (context) { | ||
var count = 0; | ||
var postPreferencesLoadHandler = function (response) { | ||
// The event usually fires twice: once on initial click, then | ||
// preferences are taken into account and it fires again. | ||
// We can't reasonably capture dithering users who change choices | ||
// several times per page load. | ||
count++; | ||
if (count === 2) { | ||
console.log(response); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the console logs or add a debug mode so we can control if they are written. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. console.log removed, PR updated. |
||
if (response.currentStatus === 'granted') { | ||
ecc_cct_log(1); | ||
} | ||
else if (response.currentStatus === 'denied') { | ||
ecc_cct_log(2); | ||
} | ||
} | ||
}; | ||
Drupal.eu_cookie_compliance('postStatusSave', postPreferencesLoadHandler); | ||
|
||
|
||
|
||
async function ecc_cct_log(choice) { | ||
const response = await fetch('/ecc-cct/js/log/' + choice).catch(error => { | ||
console.error('Error sending integer:', error); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do users need to see anything in the console? |
||
}); | ||
|
||
|
||
if (!response.ok) { | ||
throw new Error(`Response status: ${response.status}`); | ||
} | ||
else { | ||
console.log(response); | ||
} | ||
} | ||
} | ||
} | ||
})(jQuery, Drupal, drupalSettings, window.Cookies); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\ecc_cct\Controller; | ||
|
||
use Drupal\Core\Controller\ControllerBase; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* Returns responses for ECC Cookie Consent Tracker routes. | ||
*/ | ||
final class ConsentLog extends ControllerBase { | ||
|
||
/** | ||
* Handles requests to /ecc-cct/js/log/{$choice}. | ||
* | ||
* @param int $choice | ||
* The dynamic ID passed to the route. | ||
* @param \Symfony\Component\HttpFoundation\Request $request | ||
* The HTTP request object. | ||
* | ||
* @return \Symfony\Component\HttpFoundation\Response | ||
* A response object. | ||
*/ | ||
public function log(int $choice, Request $request): Response { | ||
// If this isn't turned on, bail. | ||
if (!\Drupal::config('ecc_cct.settings')->get('enable')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would probably be faster (one database read?) to use a State setting instead of config. Either way use the methods |
||
throw new ServiceUnavailableHttpException(NULL, t('Service unavailable')); | ||
} | ||
// Otherwise, let's write some data. | ||
$content = [ | ||
'status' => 'success', | ||
'message' => "Received ID: $choice", | ||
]; | ||
|
||
/** @var \Drupal\Core\Database\Connection $connection */ | ||
$connection = \Drupal::service('database'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should use a content entity instead of directly accessing the database table. It would make CRUD much easier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nah. The idea is to make this as minimalistic as possible, with the least overhead. Entities come with overhead. The DB write here couldn't be simpler, and the data extraction is a single SQL query. Entities and all of Drupal's APIs would be needless expense. In fact, we only ever want to do create and read, never update nor delete. We're doing just enough, and no more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. Don't call services like this. Use create() for dependency injection. |
||
$result = $connection->insert('ecc_cct_data') | ||
->fields([ | ||
'choice' => $choice, | ||
'timestamp' => time(), | ||
]) | ||
->execute(); | ||
|
||
// Maybe long term, we don't care about a response... | ||
// but just in case, for testing, let's leave it in. | ||
return new Response(json_encode($content), 200, ['Content-Type' => 'application/json']); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\ecc_cct\Controller; | ||
|
||
use Drupal\Core\Controller\ControllerBase; | ||
|
||
/** | ||
* Returns responses for ECC Cookie Consent Tracker routes. | ||
*/ | ||
final class EccCctController extends ControllerBase { | ||
|
||
/** | ||
* Builds the response. | ||
*/ | ||
public function build(): array { | ||
$sql = "SELECT (COUNT(CASE WHEN choice = 1 THEN 1 END) / COUNT(*)) * 100 AS optin FROM {ecc_cct_data};"; | ||
$database = \Drupal::database(); | ||
$query = $database->query($sql); | ||
$result = $query->fetchAll(); | ||
|
||
$stat = $result[0]->optin; | ||
$build['content'] = [ | ||
'#type' => 'item', | ||
'#markup' => $this->t($stat . '% of people opted into cookies.'), | ||
]; | ||
|
||
return $build; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\ecc_cct\Form; | ||
|
||
use Drupal\Core\Form\ConfigFormBase; | ||
use Drupal\Core\Form\FormStateInterface; | ||
|
||
/** | ||
* Configure ECC Cookie Consent Tracker settings for this site. | ||
*/ | ||
final class SettingsForm extends ConfigFormBase { | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function getFormId(): string { | ||
return 'ecc_cct_settings'; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function getEditableConfigNames(): array { | ||
return ['ecc_cct.settings']; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function buildForm(array $form, FormStateInterface $form_state): array { | ||
$form['enable'] = [ | ||
'#type' => 'radios', | ||
'#title' => $this->t('Enable tracking'), | ||
'#options' => [ | ||
0 => $this->t('Disabled'), | ||
1 => $this->t('Enabled'), | ||
], | ||
'#default_value' => $this->config('ecc_cct.settings')->get('enable'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add |
||
]; | ||
return parent::buildForm($form, $form_state); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function submitForm(array &$form, FormStateInterface $form_state): void { | ||
$this->config('ecc_cct.settings') | ||
->set('enable', $form_state->getValue('enable')) | ||
->save(); | ||
parent::submitForm($form, $form_state); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, what am I missing? I don't see it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abbreviation is confusing. Change to Essex County Council or ECC, like you have in other places.