CRM-19816 - Improve activity search filters
[civicrm-core.git] / api / v3 / Activity.php
index 494772a98b7b992be050599b88a79f2e736863cc..bf57eda13e2dba9f23b00d22613dbd56dcc08164 100644 (file)
@@ -223,16 +223,87 @@ function _civicrm_api3_activity_create_spec(&$params) {
 
 }
 
+/**
+ * Specify Metadata for get.
+ *
+ * @param array $params
+ */
+function _civicrm_api3_activity_get_spec(&$params) {
+  $params['tag_id'] = array(
+    'name' => 'tag_id',
+    'title' => 'Tags',
+    'description' => 'Find activities with specified tags.',
+    'type' => 1,
+    'FKClassName' => 'CRM_Core_DAO_Tag',
+    'FKApiName' => 'Tag',
+  );
+  $params['case_id'] = array(
+    'name' => 'case_id',
+    'title' => 'Cases',
+    'description' => 'Find activities within specified cases.',
+    'type' => 1,
+    'FKClassName' => 'CRM_Case_DAO_Case',
+    'FKApiName' => 'Case',
+  );
+  $params['target_contact_id'] = array(
+    'name' => 'target_contact_id',
+    'title' => 'Target Contact ID',
+    'description' => 'Find activities with specified target contact.',
+    'type' => 1,
+    'FKClassName' => 'CRM_Contact_DAO_Contact',
+    'FKApiName' => 'Contact',
+  );
+  $params['source_contact_id'] = array(
+    'name' => 'source_contact_id',
+    'title' => 'Source Contact ID',
+    'description' => 'Find activities with specified source contact.',
+    'type' => 1,
+    'FKClassName' => 'CRM_Contact_DAO_Contact',
+    'FKApiName' => 'Contact',
+  );
+  $params['assignee_contact_id'] = array(
+    'name' => 'assignee_contact_id',
+    'title' => 'Assignee Contact ID',
+    'description' => 'Find activities with specified assignee contact.',
+    'type' => 1,
+    'FKClassName' => 'CRM_Contact_DAO_Contact',
+    'FKApiName' => 'Contact',
+  );
+}
+
 /**
  * Gets a CiviCRM activity according to parameters.
  *
  * @param array $params
  *   Array per getfields documentation.
  *
- * @return array
+ * @return array API result array
  *   API result array
+ *
+ * @throws \API_Exception
+ * @throws \CiviCRM_API3_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
  */
 function civicrm_api3_activity_get($params) {
+  if (!empty($params['check_permissions']) && !CRM_Core_Permission::check('view all activities')) {
+    // In absence of view all activities permission it's possible to see a specific activity by ACL.
+    // Note still allowing view all activities to override ACLs is based on the 'don't change too much
+    // if you are not sure principle' and it could be argued that the ACLs should always be applied.
+    if (empty($params['id']) || !empty($params['contact_id'])) {
+      // We fall back to the original blunt permissions if we don't have an id to check or we are about
+      // to go to the weird place that the legacy 'contact_id' parameter takes us to.
+      throw new \Civi\API\Exception\UnauthorizedException(
+        "Cannot access activities. Required permission: 'view all activities''"
+      );
+    }
+
+    if (!CRM_Activity_BAO_Activity::checkPermission($params['id'], CRM_Core_Action::VIEW)) {
+      throw new \Civi\API\Exception\UnauthorizedException(
+        'You do not have permission to view this activity'
+      );
+    }
+  }
+
   if (!empty($params['contact_id'])) {
     $activities = CRM_Activity_BAO_Activity::getContactActivity($params['contact_id']);
     // BAO function doesn't actually return a contact ID - hack api for now & add to test so when api re-write
@@ -243,6 +314,7 @@ function civicrm_api3_activity_get($params) {
   }
   else {
     $sql = CRM_Utils_SQL_Select::fragment();
+    // Support search by activity_contact
     $options = civicrm_api3('ActivityContact', 'getoptions', array('field' => 'record_type_id'));
     $options = $options['values'];
     $activityContactOptions = array(
@@ -252,17 +324,31 @@ function civicrm_api3_activity_get($params) {
     );
     foreach ($activityContactOptions as $activityContactName => $activityContactValue) {
       if (!empty($params[$activityContactName])) {
-        // If the intent is to have multiple joins -- one for each relation -- then you would
-        // need different table aliases. Consider replacing 'ac' and passing in a '!alias' param,
-        // with a different value for each relation.
-        $sql->join(
-          'activity_' . $activityContactName,
-          'LEFT JOIN civicrm_activity_contact ac ON a.id = ac.activity_id AND ac.record_type_id = #typeId',
-          array('typeId' => $activityContactValue)
+        if (!is_array($params[$activityContactName])) {
+          $params[$activityContactName] = array('=' => $params[$activityContactName]);
+        }
+        $clause = \CRM_Core_DAO::createSQLFilter('contact_id', $params[$activityContactName]);
+        $sql->where('a.id IN (SELECT activity_id FROM civicrm_activity_contact WHERE record_type_id = #typeId AND !clause)',
+          array('#typeId' => $activityContactValue, '!clause' => $clause)
         );
-        $sql->where('ac.contact_id IN (#cid)', array(
-          'cid' => $params[$activityContactName],
-        ));
+      }
+    }
+    if (!empty($params['tag_id'])) {
+      if (!is_array($params['tag_id'])) {
+        $params['tag_id'] = array('=' => $params['tag_id']);
+      }
+      $clause = \CRM_Core_DAO::createSQLFilter('tag_id', $params['tag_id']);
+      if ($clause) {
+        $sql->where('a.id IN (SELECT entity_id FROM civicrm_entity_tag WHERE entity_table = "civicrm_activity" AND !clause)', array('!clause' => $clause));
+      }
+    }
+    if (!empty($params['case_id'])) {
+      if (!is_array($params['case_id'])) {
+        $params['case_id'] = array('=' => $params['case_id']);
+      }
+      $clause = \CRM_Core_DAO::createSQLFilter('case_id', $params['case_id']);
+      if ($clause) {
+        $sql->where('a.id IN (SELECT activity_id FROM civicrm_case_activity WHERE !clause)', array('!clause' => $clause));
       }
     }
     $activities = _civicrm_api3_basic_get(_civicrm_api3_get_BAO(__FUNCTION__), $params, FALSE, 'Activity', $sql);
@@ -305,23 +391,43 @@ function _civicrm_api3_activity_get_formatResult($params, $activities) {
   }
 
   $returns['source_contact_id'] = 1;
+  if (!empty($returns['target_contact_name'])) {
+    $returns['target_contact_id'] = 1;
+  }
+  if (!empty($returns['assignee_contact_name'])) {
+    $returns['assignee_contact_id'] = 1;
+  }
+
   foreach ($returns as $n => $v) {
     switch ($n) {
       case 'assignee_contact_id':
         foreach ($activities as $key => $activityArray) {
-          $activities[$key]['assignee_contact_id'] = CRM_Activity_BAO_ActivityAssignment::retrieveAssigneeIdsByActivityId($activityArray['id']);
+          $cids = $activities[$key]['assignee_contact_id'] = CRM_Activity_BAO_ActivityAssignment::retrieveAssigneeIdsByActivityId($activityArray['id']);
+          if ($cids && !empty($returns['assignee_contact_name'])) {
+            foreach ($cids as $cid) {
+              $activities[$key]['assignee_contact_name'][$cid] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name');
+            }
+          }
         }
         break;
 
       case 'target_contact_id':
         foreach ($activities as $key => $activityArray) {
-          $activities[$key]['target_contact_id'] = CRM_Activity_BAO_ActivityTarget::retrieveTargetIdsByActivityId($activityArray['id']);
+          $cids = $activities[$key]['target_contact_id'] = CRM_Activity_BAO_ActivityTarget::retrieveTargetIdsByActivityId($activityArray['id']);
+          if ($cids && !empty($returns['target_contact_name'])) {
+            foreach ($cids as $cid) {
+              $activities[$key]['target_contact_name'][$cid] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name');
+            }
+          }
         }
         break;
 
       case 'source_contact_id':
         foreach ($activities as $key => $activityArray) {
-          $activities[$key]['source_contact_id'] = CRM_Activity_BAO_Activity::getSourceContactID($activityArray['id']);
+          $cid = $activities[$key]['source_contact_id'] = CRM_Activity_BAO_Activity::getSourceContactID($activityArray['id']);
+          if ($cid && !empty($returns['source_contact_name'])) {
+            $activities[$key]['source_contact_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name');
+          }
         }
         break;