Skip to content

Commit

Permalink
Improve behaviour for enableAnonymousTracking
Browse files Browse the repository at this point in the history
  • Loading branch information
bencroker committed Mar 26, 2023
1 parent d9c2ab7 commit cdbe36b
Show file tree
Hide file tree
Showing 18 changed files with 123 additions and 48 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# Release Notes for Campaign

## 2.5.6 - Unreleased
## 2.6.0 - Unreleased
### Added
- Added messaging that explains why charts are not appearing in reports.

### Changed
- Campaign reports are no longer synced when the `enableAnonymousTracking` setting is enabled ([#371](https://github.com/putyourlightson/craft-campaign/issues/371)).
- Contact activity is hidden when the `enableAnonymousTracking` setting is enabled ([#371](https://github.com/putyourlightson/craft-campaign/issues/371)).
- Renamed the “Manage Reports” permission to “View Reports”.
- Users can now only edit contacts when they have edit permission for the primary site.

Expand Down Expand Up @@ -239,7 +244,7 @@
- Added a "Campaign Activity" condition rule for segmenting by contacts who have opened or clicked a link in any or a specific campaign ([#244](https://github.com/putyourlightson/craft-campaign/issues/244)).
- Added a "Default Notification Contacts" field to sendout settings.
- Added an "Export to CSV" button to all datatables in reports ([#245](https://github.com/putyourlightson/craft-campaign/issues/245)).
- Added the `enableAnonymousTracking` setting, which prevents tracking of contact interactions ([#115](https://github.com/putyourlightson/craft-campaign/issues/115)).
- Added the `enableAnonymousTracking` setting, which prevents tracking of opens and clicks ([#115](https://github.com/putyourlightson/craft-campaign/issues/115)).
- Added the `campaign/reports/anonymize` console controller that anonymizes all previously collected personal data.
- Added a list of failed contacts to sendouts that have failures ([#311](https://github.com/putyourlightson/craft-campaign/issues/311)).
- Added a link to view all contacts from the mailing list edit page ([#282](https://github.com/putyourlightson/craft-campaign/issues/282)).
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "putyourlightson/craft-campaign",
"description": "Send and manage email campaigns, contacts and mailing lists.",
"version": "2.5.6",
"version": "2.6.0",
"type": "craft-plugin",
"homepage": "https://putyourlightson.com/plugins/campaign",
"license": "proprietary",
Expand Down
2 changes: 1 addition & 1 deletion src/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

return [
'*' => [
// Whether to enable anonymous tracking
// Whether to enable anonymous tracking of opens and clicks
//'enableAnonymousTracking' => false,

// Setting to true will save email messages into local files (in storage/runtime/debug/mail) rather than actually sending them
Expand Down
8 changes: 7 additions & 1 deletion src/console/controllers/ReportsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ReportsController extends Controller
*/
public function actionAnonymize(): int
{
ContactCampaignRecord::deleteAll();
Campaign::$plugin->reports->anonymize();

$this->stdout(Craft::t('campaign', 'Personal data successfully anonymized.') . PHP_EOL, BaseConsole::FG_GREEN);

Expand All @@ -38,6 +38,12 @@ public function actionAnonymize(): int
*/
public function actionSync(): int
{
if (Campaign::$plugin->settings->enableAnonymousTracking) {
$this->stdout(Craft::t('campaign', 'Campaign reports cannot be synced when the `enableAnonymousTracking` setting is enabled.') . PHP_EOL, BaseConsole::FG_RED);

return ExitCode::OK;
}

Campaign::$plugin->reports->sync();

$this->stdout(Craft::t('campaign', 'Campaign reports successfully synced.') . PHP_EOL, BaseConsole::FG_GREEN);
Expand Down
4 changes: 3 additions & 1 deletion src/migrations/m221017_120000_sync_campaign_reports.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ class m221017_120000_sync_campaign_reports extends Migration
*/
public function safeUp(): bool
{
Campaign::$plugin->reports->sync();
if (!Campaign::$plugin->settings->enableAnonymousTracking) {
Campaign::$plugin->reports->sync();
}

return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/models/SettingsModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
class SettingsModel extends Model
{
/**
* @var bool Whether to enable anonymous tracking
* @var bool Whether to enable anonymous tracking of opens and clicks
*/
public bool $enableAnonymousTracking = false;

Expand Down
10 changes: 8 additions & 2 deletions src/resources/css/chart.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.report-chart {
border-radius: 3px;
border-radius: var(--large-border-radius);
border: 1px solid #e3e5e8;
padding: 20px 10px;
margin-top: 20px;
Expand All @@ -8,6 +8,12 @@
min-height: 100px;
}

.report-chart.empty {
font-style: italic;
margin-bottom: 40px;
min-height: 0;
}

.report-chart .select {
float: left;
margin-left: 10px;
Expand Down Expand Up @@ -49,4 +55,4 @@
float: left;
width: 30%;
padding-left: 20px;
}
}
4 changes: 2 additions & 2 deletions src/services/CampaignsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public function addContactInteraction(ContactElement $contact, SendoutElement $s
}
}

// Only save if anonymous tracking is not enabled
// Only save if anonymous tracking is disabled
if (!Campaign::$plugin->settings->enableAnonymousTracking) {
$contactCampaignRecord->save();
}
Expand Down Expand Up @@ -206,7 +206,7 @@ function() {
private function _incrementRecordColumn(ActiveRecord $record, string $column): void
{
// Respect anonymous tracking for contact campaign records.
if (Campaign::$plugin->settings->enableAnonymousTracking && $record instanceof ContactCampaignRecord) {
if ($record instanceof ContactCampaignRecord && Campaign::$plugin->settings->enableAnonymousTracking) {
return;
}

Expand Down
21 changes: 20 additions & 1 deletion src/services/ReportsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -572,14 +572,33 @@ public function getMailingListDevices(int $mailingListId, bool $detailed = false
return $this->_getDevices(ContactMailingListRecord::class, ['and', ['mailingListId' => $mailingListId], ['not', ['subscribed' => null]]], $detailed, $mailingList->getSubscribedCount(), $limit);
}

/**
* Anonymizes campaign reports.
*
* @since 2.6.0
*/
public function anonymize(): void
{
/** @var ContactCampaignRecord[] $contactCampaignRecords */
$contactCampaignRecords = ContactCampaignRecord::find()->all();

foreach ($contactCampaignRecords as $contactCampaignRecord) {
$contactCampaignRecord->opened = null;
$contactCampaignRecord->clicked = null;
$contactCampaignRecord->opens = 0;
$contactCampaignRecord->clicks = 0;
$contactCampaignRecord->links = null;
$contactCampaignRecord->save();
}
}

/**
* Syncs campaign reports.
*
* @since 2.4.0
*/
public function sync(): void
{
/** @var CampaignRecord[] $campaignRecords */
$campaignRecords = CampaignRecord::find()->all();

foreach ($campaignRecords as $campaignRecord) {
Expand Down
2 changes: 1 addition & 1 deletion src/templates/_settings/contact/index.twig
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
{{ forms.lightswitchField({
first: true,
label: "Enable Anonymous Tracking"|t('campaign'),
instructions: "Whether to enable anonymous tracking of contact interactions."|t('campaign'),
instructions: "Whether to enable anonymous tracking of opens and clicks."|t('campaign') ~ ' ' ~ macros.info('If enabling this after campaigns have already been sent, the `campaign/reports/anonymize` console command should be run to anonymizes all previously collected personal data.'|t('campaign')),
warning: (config.enableAnonymousTracking is defined ? macros.configWarning('enableAnonymousTracking')),
name: 'enableAnonymousTracking',
on: settings.enableAnonymousTracking,
Expand Down
72 changes: 46 additions & 26 deletions src/templates/reports/campaigns/_includes/report.twig
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{% macro linkInteration(campaign, interaction) -%}
{% set value = attribute(campaign, interaction) ?? 0 %}
{% if value %}
<a href="{{ campaign.getReportUrl('contact-activity', { interaction: interaction }) }}">
{% if craft.campaign.settings.enableAnonymousTracking %}
{{- value -}}
</a>
{% else %}
<a href="{{ campaign.getReportUrl('contact-activity', { interaction: interaction }) }}">
{{- value -}}
</a>
{% endif %}
{% else %}
{{ value }}
{% endif %}
Expand All @@ -19,30 +23,44 @@
<p class="light">{{ 'Campaign first sent on {date}.'|t('campaign', {date: data.dateFirstSent|datetime('full')}) }}</p>
{% endif %}

{% if data.hasChart|length %}
<div class="report-chart">
<div class="select">
<select data-id="interval">
<option value="minutes">{{ 'Minutes'|t('campaign') }}</option>
<option value="hours" selected>{{ 'Hours'|t('campaign') }}</option>
<option value="days">{{ 'Days'|t('campaign') }}</option>
<option value="months">{{ 'Months'|t('campaign') }}</option>
<option value="years">{{ 'Years'|t('campaign') }}</option>
</select>
</div>
<a href="#" data-id="refresh" class="refresh">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path fill="#8f98a3" d="M9 13.5c-2.49 0-4.5-2.01-4.5-4.5S6.51 4.5 9 4.5c1.24 0 2.36.52 3.17 1.33L10 8h5V3l-1.76 1.76C12.15 3.68 10.66 3 9 3 5.69 3 3.01 5.69 3.01 9S5.69 15 9 15c2.97 0 5.43-2.16 5.9-5h-1.52c-.46 2-2.24 3.5-4.38 3.5z"/></svg>
</a>
<div class="spinner big"></div>
<div data-id="chart"></div>
{% if craft.campaign.settings.enableAnonymousTracking %}
<div class="report-chart empty">
<p class="light">
{{ 'Chart unavailable when anonymous tracking is enabled.'|t('campaign') }}
</p>
</div>
{% else %}
{% if data.hasChart|length %}
<div class="report-chart">
<div class="select">
<select data-id="interval">
<option value="minutes">{{ 'Minutes'|t('campaign') }}</option>
<option value="hours" selected>{{ 'Hours'|t('campaign') }}</option>
<option value="days">{{ 'Days'|t('campaign') }}</option>
<option value="months">{{ 'Months'|t('campaign') }}</option>
<option value="years">{{ 'Years'|t('campaign') }}</option>
</select>
</div>
<a href="#" data-id="refresh" class="refresh">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18"><path fill="#8f98a3" d="M9 13.5c-2.49 0-4.5-2.01-4.5-4.5S6.51 4.5 9 4.5c1.24 0 2.36.52 3.17 1.33L10 8h5V3l-1.76 1.76C12.15 3.68 10.66 3 9 3 5.69 3 3.01 5.69 3.01 9S5.69 15 9 15c2.97 0 5.43-2.16 5.9-5h-1.52c-.46 2-2.24 3.5-4.38 3.5z"/></svg>
</a>
<div class="spinner big"></div>
<div data-id="chart"></div>
</div>

{% js %}
new Campaign.Chart({
action: 'campaign/reports/get-campaign-chart-data',
campaignId: '{{ campaign.id }}'
});
{% endjs %}
{% js %}
new Campaign.Chart({
action: 'campaign/reports/get-campaign-chart-data',
campaignId: '{{ campaign.id }}'
});
{% endjs %}
{% else %}
<div class="report-chart empty">
<p class="light">
{{ 'No data to display.'|t('campaign') }}
</p>
</div>
{% endif %}
{% endif %}

{% if data.campaign %}
Expand Down Expand Up @@ -114,8 +132,10 @@

{% set limit = 5 %}

<h2>{{ "Contact Activity"|t('campaign') }}</h2>
{% include 'campaign/reports/campaigns/_includes/contact-activity' with { contactActivity: craft.campaign.reports.getCampaignContactActivity(campaign.id, null, limit), reportUrl: url('campaign/reports/campaigns/' ~ campaign.id ~ '/contact-activity') } %}
{% if not craft.campaign.settings.enableAnonymousTracking %}
<h2>{{ "Contact Activity"|t('campaign') }}</h2>
{% include 'campaign/reports/campaigns/_includes/contact-activity' with { contactActivity: craft.campaign.reports.getCampaignContactActivity(campaign.id, null, limit), reportUrl: url('campaign/reports/campaigns/' ~ campaign.id ~ '/contact-activity') } %}
{% endif %}

<h2>{{ "Links"|t('campaign') }}</h2>
{% include 'campaign/reports/campaigns/_includes/links' with { links: craft.campaign.reports.getCampaignLinks(campaign.id, limit), reportUrl: url('campaign/reports/campaigns/' ~ campaign.id ~ '/links') } %}
Expand Down
2 changes: 1 addition & 1 deletion src/templates/reports/campaigns/_view.twig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

{% block pageTitle %}
{{ parent() }}
{% if currentUser.can('campaign:campaigns') %}
{% if campaign.canSave(currentUser) %}
<a href="{{ campaign.cpEditUrl }}" class="btn">{{ 'Edit'|t('campaign') }}</a>
{% endif %}
{% endblock %}
Expand Down
6 changes: 4 additions & 2 deletions src/templates/reports/contacts/_includes/report.twig
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@

{% set limit = 10 %}

<h2>{{ "Campaign Activity"|t('campaign') }}</h2>
{% include 'campaign/reports/contacts/_includes/campaign-activity' with { campaignActivity: craft.campaign.reports.getContactCampaignActivity(contact.id, limit) } %}
{% if not craft.campaign.settings.enableAnonymousTracking %}
<h2>{{ "Campaign Activity"|t('campaign') }}</h2>
{% include 'campaign/reports/contacts/_includes/campaign-activity' with { campaignActivity: craft.campaign.reports.getContactCampaignActivity(contact.id, limit) } %}
{% endif %}

<h2>{{ "Mailing List Activity"|t('campaign') }}</h2>
{% include 'campaign/reports/contacts/_includes/mailinglist-activity' with { mailingListActivity: craft.campaign.reports.getContactMailingListActivity(contact.id, limit) } %}
Expand Down
10 changes: 8 additions & 2 deletions src/templates/reports/mailinglists/_includes/report.twig
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,22 @@
<div data-id="chart"></div>
</div>

<br>

{% js %}
new Campaign.Chart({
action: 'campaign/reports/get-mailing-list-chart-data',
mailingListId: '{{ mailingList.id }}'
});
{% endjs %}
{% else %}
<div class="report-chart empty">
<p class="light">
{{ 'No data to display.'|t('campaign') }}
</p>
</div>
{% endif %}

<br/>

<h2>{{ "Mailing List Details"|t('campaign') }}</h2>

<table class="data fullwidth collapsible">
Expand Down
2 changes: 1 addition & 1 deletion src/templates/reports/mailinglists/_view.twig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

{% block pageTitle %}
{{ parent() }}
{% if currentUser.can('campaign:mailingLists') %}
{% if mailingList.canSave(currentUser) %}
<a href="{{ mailingList.cpEditUrl }}" class="btn">{{ 'Edit'|t('campaign') }}</a>
{% endif %}
{% endblock %}
Expand Down
5 changes: 4 additions & 1 deletion src/translations/de/campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
'Cancel' => 'Abbrechen',
'Cancelled' => 'Abgebrochen',
'Changing this can lead to sent campaigns not being reachable and other undesirable results.' => 'Ändern der Einstellung kann dazu führen, dass gesendete Kampagnen nicht mehr erreichbar sind oder andere unerwünschte Effekte auftreten.',
'Chart unavailable when anonymous tracking is enabled.' => '',
'Choose a campaign' => 'Wählen Sie eine Kampagne',
'Choose a CSV file (comma-separated values) to import contact data. The first line of the file should contain the column headers. The following contact fields are available:' => 'Wählen Sie eine CSV-Datei aus, um Kontakdaten zu importieren. Die erste Zeile sollte die Spaltennamen enthalten. Die folgenden Kontakt-Felder sind verfügbar:',
'Choose a mailing list to sync. ' => 'Wählen Sie eine Mailing-Liste zum Synchronisieren.',
Expand Down Expand Up @@ -296,6 +297,7 @@
'How you’ll refer to this mailing list type in the templates.' => 'Wie Sie sich in Templates auf diesen Mailing-Listen-Typ beziehen.',
'HTML Body' => 'HTML-Inhalt',
'HTML Template' => 'HTML-Template',
'If enabling this after campaigns have already been sent, the `campaign/reports/anonymize` console command should be run to anonymizes all previously collected personal data.' => '',
'Import a user group and subscribe the users that belong to it to one or more mailing lists.' => 'Importiere eine Benutzergruppe und füge deren Benutzer zu einer oder mehreren Mailing-Liste(n) hinzu.',
'Import contacts' => 'Kontakte importieren',
'Import emails addresses and contact data from a CSV file.' => 'Importiere E-Mail-Adresse und Kontaktdaten aus einer CSV-Datei.',
Expand Down Expand Up @@ -392,6 +394,7 @@
'No contact activity for this mailing list.' => 'Keine Kontakt-Aktivität für diese Mailing-Liste',
'No contact activity.' => 'Keine Kontakt-Aktivität.',
'No contacts have been assigned to this mailing list.' => 'Dieser Mailing-Liste wurden keine Kontakte zugewiesen.',
'No data to display.' => '',
'No devices found.' => 'Keine Geräte gefunden.',
'No from name and email exists for this site.' => 'Es existieren kein Von-Name und keine Von-E-Mail für diese Website.',
'No imports exist.' => '',
Expand Down Expand Up @@ -672,7 +675,7 @@
'Whether contacts should be subscribed to the mailing list even if they were previously unsubscribed.' => 'Ob Kontakte zur Mailing-Liste hinzugefügt werden sollen, auch wenn sie vorher schon einmal ausgetragen wurden.',
'Whether the contact needs to verify their email address by clicking on a link in a verification email that will be sent to them after submitting a subscribe form (highly recommended).' => 'Ob der Kontakt seine E-Mail-Adresse durch Klick auf einen Link in einer Verifizierungs-E-Mail bestätigen muss, die ihm geschickt wird, nachdem er ein Anmeldeformular abgeschickt hat (dringend empfohlen).',
'Whether the sendout can be sent to contacts multiple times.' => 'Ob die Sendung mehrmals an Kontakte verschickt werden kann.',
'Whether to enable anonymous tracking of contact interactions.' => '',
'Whether to enable anonymous tracking of opens and clicks.' => '',
'Years' => 'Jahre',
'You can use the following URL to queue pending sendouts. Including the optional `run` parameter will immediately run any queued jobs.' => 'Sie können die folgende URL nutzen, um anstehende Sendungen in der Warteschlange zu platzieren. Durch Hinzufügen des optionalen `run` Parameters wird die Warteschlange sofort abgearbeitet.',
'You have successfully subscribed to the mailing list.' => 'Sie haben sich erfolgreich in der Mailing-Liste angemeldet',
Expand Down
5 changes: 4 additions & 1 deletion src/translations/en/campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
'Cancel' => '',
'Cancelled' => '',
'Changing this can lead to sent campaigns not being reachable and other undesirable results.' => '',
'Chart unavailable when anonymous tracking is enabled.' => '',
'Choose a campaign' => '',
'Choose a CSV file (comma-separated values) to import contact data. The first line of the file should contain the column headers. The following contact fields are available:' => '',
'Choose a mailing list to sync. ' => '',
Expand Down Expand Up @@ -295,6 +296,7 @@
'How you’ll refer to this mailing list type in the templates.' => '',
'HTML Body' => '',
'HTML Template' => '',
'If enabling this after campaigns have already been sent, the `campaign/reports/anonymize` console command should be run to anonymizes all previously collected personal data.' => '',
'Import a user group and subscribe the users that belong to it to one or more mailing lists.' => '',
'Import contacts' => '',
'Import emails addresses and contact data from a CSV file.' => '',
Expand Down Expand Up @@ -391,6 +393,7 @@
'No contact activity for this mailing list.' => '',
'No contact activity.' => '',
'No contacts have been assigned to this mailing list.' => '',
'No data to display.' => '',
'No devices found.' => '',
'No from name and email exists for this site.' => '',
'No imports exist.' => '',
Expand Down Expand Up @@ -671,7 +674,7 @@
'Whether contacts should be subscribed to the mailing list even if they were previously unsubscribed.' => '',
'Whether the contact needs to verify their email address by clicking on a link in a verification email that will be sent to them after submitting a subscribe form (highly recommended).' => '',
'Whether the sendout can be sent to contacts multiple times.' => '',
'Whether to enable anonymous tracking of contact interactions.' => '',
'Whether to enable anonymous tracking of opens and clicks.' => '',
'Years' => '',
'You can use the following URL to queue pending sendouts. Including the optional `run` parameter will immediately run any queued jobs.' => '',
'You have successfully subscribed to the mailing list.' => '',
Expand Down
Loading

0 comments on commit cdbe36b

Please sign in to comment.