Skip to content
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

SearchKit - Add CiviMail integration #22808

Merged
merged 1 commit into from
Mar 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ext/search_kit/Civi/Api4/Action/SearchDisplay/GetSearchTasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ public function _run(\Civi\Api4\Generic\Result $result) {
],
];
}
if (\CRM_Core_Component::isEnabled('CiviMail') && (
\CRM_Core_Permission::access('CiviMail') || !$this->checkPermissions ||
(\CRM_Mailing_Info::workflowEnabled() && \CRM_Core_Permission::check('create mailings'))
)) {
$tasks[$entity['name']]['contact.mailing'] = [
'title' => E::ts('Email - schedule/send via CiviMail'),
'uiDialog' => ['templateUrl' => '~/crmSearchTasks/crmSearchTaskMailing.html'],
'icon' => 'fa-paper-plane',
];
}
}

if ($entity['name'] === 'Contribution') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
EST_BATCH_TIME = 5;

this.$onInit = function() {
if (ctrl.action === 'create') {
ctrl.ids = [0];
}
totalBatches = Math.ceil(ctrl.ids.length / BATCH_SIZE);
runBatch();
};
Expand All @@ -50,7 +53,7 @@
records.push(record);
});
});
} else {
} else if (ctrl.action !== 'create') {
// For other batch actions (update, delete), add supplied ids to the where clause
params.where = params.where || [];
params.where.push([ctrl.idField || 'id', 'IN', ctrl.ids.slice(ctrl.first, ctrl.last)]);
Expand All @@ -60,7 +63,9 @@
stopIncrementer();
ctrl.progress = Math.floor(100 * ++currentBatch / totalBatches);
if (ctrl.last >= ctrl.ids.length) {
$timeout(ctrl.success, 500);
$timeout(function() {
ctrl.success({result: result});
}, 500);
} else {
runBatch();
}
Expand Down
73 changes: 73 additions & 0 deletions ext/search_kit/ang/crmSearchTasks/crmSearchTaskMailing.ctrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
(function(angular, $, _) {
"use strict";

angular.module('crmSearchTasks').controller('crmSearchTaskMailing', function($scope, crmApi4, searchTaskBaseTrait) {
var ts = $scope.ts = CRM.ts('org.civicrm.search_kit'),
// Combine this controller with model properties (ids, entity, entityInfo) and searchTaskBaseTrait
ctrl = angular.extend(this, $scope.model, searchTaskBaseTrait),
templateTypes;

this.entityTitle = this.getEntityTitle();

// This option is needed to determine whether the mailing will be handled by CiviMail or Mosaico
crmApi4({
templateTypes: ['Mailing', 'getFields', {
loadOptions: ['id'],
where: [['name', '=', 'template_type']]
}, ['options']],
recipientCount: ['Contact', 'get', {
select: ['row_count'],
join: [['Email AS email', 'INNER', ['id', '=', 'email.contact_id']]],
where: [['id', 'IN', ctrl.ids], ['do_not_email', '!=', true], ['is_opt_out', '!=', true], ['email.on_hold', '=', 0]],
groupBy: ['id']
}]
}).then(function(results) {
templateTypes = results.templateTypes[0];
ctrl.recipientCount = results.recipientCount.count;
});

this.submit = function() {
var contacts = _.transform(ctrl.ids, function(records, cid) {
records.push({contact_id: cid});
});
ctrl.start({
values: {
title: 'Hidden Group ' + Date.now(),
is_hidden: true,
'group_type:name': ['Mailing List'],
},
chain: {
contacts: ['GroupContact', 'save', {
defaults: {group_id: '$id'},
records: contacts
}],
mailing: ['Mailing', 'create', {
values: {
name: ctrl.name,
template_type: templateTypes[0].id
}
}, 0],
mailingGroup: ['MailingGroup', 'create', {
values: {
group_type: 'Include',
'entity_table:name': 'Group',
entity_id: '$id',
mailing_id: '$mailing.id'
},
}, 0]
}
});
};


this.onSuccess = function(result) {
window.location = CRM.url('civicrm/a#/mailing/' + result[0].mailing.id);
};

this.onError = function() {
CRM.alert(ts('An error occurred while attempting to create mailing.'), ts('Error'), 'error');
this.cancel();
};

});
})(angular, CRM.$, CRM._);
34 changes: 34 additions & 0 deletions ext/search_kit/ang/crmSearchTasks/crmSearchTaskMailing.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<div id="bootstrap-theme" crm-dialog="crmSearchTask">
<form name="crmSearchTaskMailingForm" ng-controller="crmSearchTaskMailing as $ctrl">
<div class="alert alert-info">
<p>{{:: ts('Compose and send a mass-mailing to the %1 selected contacts (you will be able to add or exclude additional groups of contacts in the next step).', {1: $ctrl.ids.length}) }}</p>
</div>
<label for="crm-search-task-mailing-name">{{:: ts('Mailing Name') }} <span class="crm-marker">*</span></label>
<input required class="form-control" id="crm-search-task-mailing-name" ng-model="$ctrl.name">
<br>
<div ng-if="!$ctrl.run" class="alert" ng-class="{'alert-success': $ctrl.recipientCount === $ctrl.ids.length, 'alert-danger': $ctrl.recipientCount === 0, 'alert-warning': $ctrl.recipientCount !== 0 && $ctrl.recipientCount &lt; $ctrl.ids.length}">
<div ng-if="!$ctrl.recipientCount && $ctrl.recipientCount !== 0">
<i class="crm-i fa-spinner fa-spin"></i>
{{:: ts('Checking recipients...') }}
</div>
<div ng-if="$ctrl.recipientCount === 0">
<i class="crm-i fa-exclamation-triangle"></i>
{{:: ts('None of the selected contacts are eligible to receive mailings (due to lack of email address or unsubscribe status).') }}
</div>
<div ng-if="$ctrl.recipientCount && $ctrl.recipientCount &lt; $ctrl.ids.length">
<i class="crm-i fa-exclamation-triangle"></i>
{{:: ts('%1 of the selected contacts cannot receive mailings (due to lack of email address or unsubscribe status).', {1: $ctrl.ids.length - $ctrl.recipientCount}) }}
</div>
<div ng-if="$ctrl.recipientCount === $ctrl.ids.length">
<i class="crm-i fa-check-circle"></i>
{{:: ts('All of the selected contacts have active email addresses.') }}
</div>
</div>
<div ng-if="$ctrl.run" class="crm-search-task-progress">
<h5>{{:: ts('Creating mailing...') }}</h5>
<crm-search-batch-runner entity="'Group'" action="create" params="$ctrl.run" success="$ctrl.onSuccess(result)" error="$ctrl.onError()" ></crm-search-batch-runner>
</div>
<crm-dialog-button text="ts('Cancel')" icons="{primary: 'fa-times'}" on-click="$ctrl.cancel()" disabled="$ctrl.run" />
<crm-dialog-button text="ts('Create Mailing')" icons="{primary: 'fa-paper-plane'}" on-click="$ctrl.submit()" disabled="!$ctrl.recipientCount || $ctrl.run || !crmSearchTaskMailingForm.$valid" />
</form>
</div>