diff --git a/CRM/Contact/Form/Merge.php b/CRM/Contact/Form/Merge.php
index 8894c58df6a0..f5ffdd29443d 100644
--- a/CRM/Contact/Form/Merge.php
+++ b/CRM/Contact/Form/Merge.php
@@ -44,6 +44,11 @@ class CRM_Contact_Form_Merge extends CRM_Core_Form {
var $_contactType = NULL;
+ /**
+ * @var array
+ */
+ public $criteria = array();
+
/**
* Query limit to be retained in the urls.
*
@@ -74,8 +79,9 @@ public function preProcess() {
$this->_gid = $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE);
$this->_mergeId = CRM_Utils_Request::retrieve('mergeId', 'Positive', $this, FALSE);
$this->limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this, FALSE);
+ $this->criteria = CRM_Utils_Request::retrieve('criteria', 'Json', $this, FALSE, '{}');
- $urlParams = ['reset' => 1, 'rgid' => $this->_rgid, 'gid' => $this->_gid, 'limit' => $this->limit];
+ $urlParams = ['reset' => 1, 'rgid' => $this->_rgid, 'gid' => $this->_gid, 'limit' => $this->limit, 'criteria' => $this->criteria];
$this->bounceIfInvalid($this->_cid, $this->_oid);
@@ -100,7 +106,7 @@ public function preProcess() {
CRM_Core_Session::singleton()->pushUserContext($browseUrl);
}
- $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid);
+ $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid, json_decode($this->criteria, TRUE));
$join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
$where = "de.id IS NULL";
@@ -300,7 +306,7 @@ public function postProcess() {
$message = '
- ' . ts('%1 has been updated.', array(1 => $name)) . '
- ' . ts('Contact ID %1 has been deleted.', array(1 => $this->_oid)) . '
';
CRM_Core_Session::setStatus($message, ts('Contacts Merged'), 'success');
- $urlParams = ['reset' => 1, 'cid' => $this->_cid, 'rgid' => $this->_rgid, 'gid' => $this->_gid, 'limit' => $this->limit];
+ $urlParams = ['reset' => 1, 'cid' => $this->_cid, 'rgid' => $this->_rgid, 'gid' => $this->_gid, 'limit' => $this->limit, 'criteria' => $this->criteria];
$contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', ['reset' => 1, 'cid' => $this->_cid]);
if (!empty($formValues['_qf_Merge_submit'])) {
@@ -314,7 +320,7 @@ public function postProcess() {
}
if ($this->next && $this->_mergeId) {
- $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $this->_gid);
+ $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $this->_gid, json_decode($this->criteria, TRUE));
$join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
$where = "de.id IS NULL";
diff --git a/CRM/Contact/Page/AJAX.php b/CRM/Contact/Page/AJAX.php
index 09f396b4da2a..4cbc87f08172 100644
--- a/CRM/Contact/Page/AJAX.php
+++ b/CRM/Contact/Page/AJAX.php
@@ -646,13 +646,16 @@ public static function getDedupes() {
$gid = CRM_Utils_Request::retrieve('gid', 'Positive');
$rgid = CRM_Utils_Request::retrieve('rgid', 'Positive');
+ $null = NULL;
+ $criteria = CRM_Utils_Request::retrieve('criteria', 'Json', $null, FALSE, '{}');
$selected = isset($_REQUEST['selected']) ? CRM_Utils_Type::escape($_REQUEST['selected'], 'Integer') : 0;
if ($rowCount < 0) {
$rowCount = 0;
}
$whereClause = $orderByClause = '';
- $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid);
+ $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, json_decode($criteria, TRUE));
+
$searchRows = array();
$searchParams = self::getSearchOptionsFromRequest();
@@ -814,6 +817,7 @@ public static function getDedupes() {
'oid' => $pairInfo['entity_id2'],
'action' => 'update',
'rgid' => $rgid,
+ 'criteria' => $criteria,
'limit' => CRM_Utils_Request::retrieve('limit', 'Integer'),
];
if ($gid) {
@@ -1014,8 +1018,9 @@ public static function toggleDedupeSelect() {
$gid = CRM_Utils_Type::escape($_REQUEST['gid'], 'Integer');
$pnid = $_REQUEST['pnid'];
$isSelected = CRM_Utils_Type::escape($_REQUEST['is_selected'], 'Boolean');
+ $criteria = CRM_Utils_Request::retrieve('criteria', 'Json', $null, FALSE, '{}');
- $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid);
+ $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, json_decode($criteria, TRUE));
$params = array(
1 => array($isSelected, 'Boolean'),
diff --git a/CRM/Contact/Page/DedupeFind.php b/CRM/Contact/Page/DedupeFind.php
index 285c5bc820d1..d2acfdfcdc9b 100644
--- a/CRM/Contact/Page/DedupeFind.php
+++ b/CRM/Contact/Page/DedupeFind.php
@@ -63,8 +63,10 @@ public function run() {
$limit = CRM_Utils_Request::retrieve('limit', 'Integer', $this);
$rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this);
$cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE, 0);
- // Using a placeholder for criteria as it is intended to be able to pass this later.
- $criteria = array();
+
+ $criteria = CRM_Utils_Request::retrieve('criteria', 'Json', $this, FALSE, '{}');
+ $this->assign('criteria', $criteria);
+
$isConflictMode = ($context == 'conflicts');
if ($cid) {
$this->_cid = $cid;
@@ -79,8 +81,10 @@ public function run() {
'rgid' => $rgid,
'gid' => $gid,
'limit' => $limit,
+ 'criteria' => $criteria,
);
$this->assign('urlQuery', CRM_Utils_System::makeQueryString($urlQry));
+ $criteria = json_decode($criteria, TRUE);
if ($context == 'search') {
$context = 'search';
diff --git a/CRM/Contact/Page/DedupeMerge.php b/CRM/Contact/Page/DedupeMerge.php
index d3cc7998545e..8dc0e29333ba 100644
--- a/CRM/Contact/Page/DedupeMerge.php
+++ b/CRM/Contact/Page/DedupeMerge.php
@@ -52,13 +52,13 @@ public function run() {
* Build a queue of tasks by dividing dupe pairs in batches.
*/
public static function getRunner() {
+
$rgid = CRM_Utils_Request::retrieveValue('rgid', 'Positive');
$gid = CRM_Utils_Request::retrieveValue('gid', 'Positive');
$limit = CRM_Utils_Request::retrieveValue('limit', 'Positive');
$action = CRM_Utils_Request::retrieveValue('action', 'String');
$mode = CRM_Utils_Request::retrieveValue('mode', 'String', 'safe');
-
- $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid);
+ $criteria = CRM_Utils_Request::retrieve('criteria', 'Json', $null, FALSE, '{}');
$urlQry = array(
'reset' => 1,
@@ -66,8 +66,12 @@ public static function getRunner() {
'rgid' => $rgid,
'gid' => $gid,
'limit' => $limit,
+ 'criteria' => $criteria,
);
+ $criteria = json_decode($criteria, TRUE);
+ $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, $criteria);
+
if ($mode == 'aggressive' && !CRM_Core_Permission::check('force merge duplicate contacts')) {
CRM_Core_Session::setStatus(ts('You do not have permission to force merge duplicate contact records'), ts('Permission Denied'), 'error');
CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry));
@@ -101,7 +105,7 @@ public static function getRunner() {
for ($i = 1; $i <= ceil($total / self::BATCHLIMIT); $i++) {
$task = new CRM_Queue_Task(
array('CRM_Contact_Page_DedupeMerge', 'callBatchMerge'),
- array($rgid, $gid, $mode, self::BATCHLIMIT, $isSelected),
+ array($rgid, $gid, $mode, self::BATCHLIMIT, $isSelected, $criteria),
"Processed " . $i * self::BATCHLIMIT . " pair of duplicates out of " . $total
);
@@ -131,11 +135,12 @@ public static function getRunner() {
* 'safe' mode or 'force' mode.
* @param int $batchLimit
* @param int $isSelected
+ * @param array $criteria
*
* @return int
*/
- public static function callBatchMerge(CRM_Queue_TaskContext $ctx, $rgid, $gid, $mode = 'safe', $batchLimit, $isSelected) {
- CRM_Dedupe_Merger::batchMerge($rgid, $gid, $mode, $batchLimit, $isSelected);
+ public static function callBatchMerge(CRM_Queue_TaskContext $ctx, $rgid, $gid, $mode = 'safe', $batchLimit, $isSelected, $criteria) {
+ CRM_Dedupe_Merger::batchMerge($rgid, $gid, $mode, $batchLimit, $isSelected, $criteria);
return CRM_Queue_Task::TASK_SUCCESS;
}
diff --git a/CRM/Utils/Rule.php b/CRM/Utils/Rule.php
index 0c6473c70a67..d3029447ad9c 100644
--- a/CRM/Utils/Rule.php
+++ b/CRM/Utils/Rule.php
@@ -813,6 +813,25 @@ public static function xssString($value) {
}
}
+ /**
+ * Validate json string for xss
+ *
+ * @param string $value
+ *
+ * @return bool
+ * False if invalid, true if valid / safe.
+ */
+ public static function json($value) {
+ if (!self::xssString($value)) {
+ return FALSE;
+ }
+ $array = json_decode($value, TRUE);
+ if (!$array || !is_array($array)) {
+ return FALSE;
+ }
+ return self::arrayValue($array);
+ }
+
/**
* @param $path
*
@@ -942,4 +961,24 @@ public static function checkExtesnionKeyIsValid($key = NULL) {
return TRUE;
}
+ /**
+ * Validate array recursively checking keys and values.
+ *
+ * @param array $array
+ * @return bool
+ */
+ protected static function arrayValue($array) {
+ foreach ($array as $key => $item) {
+ if (is_array($item)) {
+ if (!self::xssString($key) || !self::arrayValue($item)) {
+ return FALSE;
+ }
+ }
+ if (!self::xssString($key) || !self::xssString($item)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
}
diff --git a/CRM/Utils/Type.php b/CRM/Utils/Type.php
index 29b05579aec4..cf50eabba9c0 100644
--- a/CRM/Utils/Type.php
+++ b/CRM/Utils/Type.php
@@ -422,6 +422,7 @@ public static function validate($data, $type, $abort = TRUE, $name = 'One of par
'MysqlOrderByDirection',
'MysqlOrderBy',
'ExtensionKey',
+ 'Json',
);
if (!in_array($type, $possibleTypes)) {
if ($isThrowException) {
@@ -530,6 +531,12 @@ public static function validate($data, $type, $abort = TRUE, $name = 'One of par
return $data;
}
break;
+
+ case 'Json':
+ if (CRM_Utils_Rule::json($data)) {
+ return $data;
+ }
+ break;
}
if ($abort) {
diff --git a/templates/CRM/Contact/Page/DedupeFind.tpl b/templates/CRM/Contact/Page/DedupeFind.tpl
index 17e2edc09d51..5c0a45ae4107 100644
--- a/templates/CRM/Contact/Page/DedupeFind.tpl
+++ b/templates/CRM/Contact/Page/DedupeFind.tpl
@@ -324,6 +324,9 @@
var is_selected = CRM.$('.crm-dedupe-select-all').prop('checked') ? 1 : 0;
}
+ var criteria = {/literal}'{$criteria|escape}'{literal};
+ criteria = criteria.length > 0 ? criteria : 0;
+
var dataUrl = {/literal}"{crmURL p='civicrm/ajax/toggleDedupeSelect' h=0 q='snippet=4'}"{literal};
var rgid = {/literal}"{$rgid}"{literal};
var gid = {/literal}"{$gid}"{literal};
@@ -331,7 +334,7 @@
rgid = rgid.length > 0 ? rgid : 0;
gid = gid.length > 0 ? gid : 0;
- CRM.$.post(dataUrl, {pnid: id, rgid: rgid, gid: gid, is_selected: is_selected}, function (data) {
+ CRM.$.post(dataUrl, {pnid: id, rgid: rgid, gid: gid, is_selected: is_selected, criteria : criteria}, function (data) {
// nothing to do for now
}, 'json');
}