Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
<?php

/**
* @file
*/

// Include CRM_Core_Error directly for API v3.
require_once 'CRM/Core/Error.php';
use Civi\Api4\Phone;
use Civi\Api4\Participant;
use CRM\Civiglific\GlificClient;

/**
* Define API spec.
*/
function _civicrm_api3_civicrm_glific_civicrm_glific_send_whatsapp_qr_cron_spec(&$spec) {}

/**
* Cron job to trigger a WhatsApp Flow for Bangalore Chaupal.
*/
function civicrm_api3_civiglific_civicrm_glific_send_whatsapp_qr_cron($params) {
error_log('testing: Entered civicrm_api3_civiglific_civicrm_glific_send_whatsapp_qr_cron');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove extensive debug logging statements

The function contains numerous error_log statements that appear to be for debugging purposes. These should be removed or replaced with proper logging mechanisms before production deployment.

Consider using CiviCRM's built-in logging system (CRM_Core_Error::debug_log_message()) for important operational messages and removing verbose debug output.

Also applies to: 27-28, 36-37, 45-46, 54-55, 62-63, 65-66, 69-70, 77-78, 84-85, 88-89, 93-93

🤖 Prompt for AI Agents
In
wp-content/civi-extensions/civiglific/api/v3/Civiglific/CivicrmGlificSendWhatsappQrCron.php
around lines 22, 27-28, 36-37, 45-46, 54-55, 62-63, 65-66, 69-70, 77-78, 84-85,
88-89, and 93, remove all error_log debug statements used for verbose debugging.
Replace any important operational messages with calls to CiviCRM's logging
system using CRM_Core_Error::debug_log_message() to ensure proper logging
practices before production deployment.

$eventId = $params['event_id'] ?? 35;
$returnValues = [];

try {
error_log('testing: Fetching participants for event ID: ' . $eventId);
$participants = Participant::get(FALSE)
->addSelect('id', 'contact_id')
->addWhere('event_id', '=', $eventId)
->addWhere('status_id:label', '=', 'Registered')
->setLimit(0)
->execute();

$glificClient = new GlificClient();
error_log('testing: Initialized GlificClient');

foreach ($participants as $participant) {
$contactId = $participant['contact_id'];

$participant_id = qrcodecheckin_participant_id_for_contact_id($contactId, $eventId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Add missing dependency includes

The file uses functions from the qrcodecheckin extension (qrcodecheckin_participant_id_for_contact_id, qrcodecheckin_get_code, qrcodecheckin_create_image, qrcodecheckin_get_image_url) without including the required files. This could cause fatal errors if the extension isn't properly loaded.

Add the necessary require/include statement at the beginning of the file:

 // Include CRM_Core_Error directly for API v3.
 require_once 'CRM/Core/Error.php';
+// Include qrcodecheckin functions
+require_once __DIR__ . '/../../net.ourpowerbase.qrcodecheckin-2.1.2/qrcodecheckin.php';
 use Civi\Api4\Phone;

Verify the correct path to the qrcodecheckin extension:

Also applies to: 44-44, 48-48, 53-53


🏁 Script executed:

#!/bin/bash
# Description: Find the correct relative path to qrcodecheckin.php from the current file location

# Search for qrcodecheckin.php file
fd -t f "qrcodecheckin.php" | grep -v "/vendor/" | head -10

# Check if the extensions are in the same parent directory
fd -t d "net.ourpowerbase.qrcodecheckin" wp-content/civi-extensions/
fd -t d "civiglific" wp-content/civi-extensions/

Length of output: 536


Add missing qrcodecheckin include to avoid fatal errors

The cron class calls several qrcodecheckin_* functions without loading the extension, which will trigger undefined‐function errors if the extension isn’t already autoloaded. Add the require once at the top of the file, before the first qrcodecheckin_* call.

• File: wp-content/civi-extensions/civiglific/api/v3/Civiglific/CivicrmGlificSendWhatsappQrCron.php
• Insert before line 41 (and ahead of any qrcodecheckin_* invocation)

 require_once 'CRM/Core/Error.php';
+// Include qrcodecheckin functions
+require_once __DIR__ . '/../../../../net.ourpowerbase.qrcodecheckin-2.1.2/qrcodecheckin.php';
 use Civi\Api4\Phone;

This makes the following functions available and prevents fatal errors:

  • qrcodecheckin_participant_id_for_contact_id
  • qrcodecheckin_get_code
  • qrcodecheckin_create_image
  • qrcodecheckin_get_image_url
🤖 Prompt for AI Agents
In
wp-content/civi-extensions/civiglific/api/v3/Civiglific/CivicrmGlificSendWhatsappQrCron.php
before line 41, add a require_once statement to include the qrcodecheckin
extension file. This will ensure that all qrcodecheckin_* functions used in the
file are defined and prevent fatal undefined-function errors during execution.


if ($participant_id) {
$code = qrcodecheckin_get_code($participant_id);
error_log('code: ' . print_r($code, TRUE));

// First ensure the image file is created.
qrcodecheckin_create_image($code, $participant_id);

// Get the absolute link to the image that will display the QR code.
$query = NULL;
$absolute = TRUE;
$link = qrcodecheckin_get_image_url($code);
error_log('link: ' . print_r($link, TRUE));

$values[$contact_id]['qrcodecheckin.qrcode_url_' . $event_id] = $link;
$values[$contact_id]['qrcodecheckin.qrcode_html_' . $event_id] = E::ts('<div><img alt="QR Code with link to checkin page" src="%1"></div><div>You should see a QR code above which will be used to quickly check you into the event. If you do not see a code display above, please enable the display of images in your email program or try accessing it <a href="%1">directly</a>. You may want to take a screen grab of your QR Code in case you need to display it when you do not have Internet access.</div>', [
1 => $link,
]);
Comment on lines +56 to +59

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix undefined variable $contact_id

The code uses $contact_id which is undefined. The correct variable name is $contactId as defined on line 39.

-        $values[$contact_id]['qrcodecheckin.qrcode_url_' . $event_id] = $link;
-        $values[$contact_id]['qrcodecheckin.qrcode_html_' . $event_id] = E::ts('<div><img alt="QR Code with link to checkin page" src="%1"></div><div>You should see a QR code above which will be used to quickly check you into the event. If you do not see a code display above, please enable the display of images in your email program or try accessing it <a href="%1">directly</a>. You may want to take a screen grab of your QR Code in case you need to display it when you do not have Internet access.</div>', [
+        $values[$contactId]['qrcodecheckin.qrcode_url_' . $eventId] = $link;
+        $values[$contactId]['qrcodecheckin.qrcode_html_' . $eventId] = E::ts('<div><img alt="QR Code with link to checkin page" src="%1"></div><div>You should see a QR code above which will be used to quickly check you into the event. If you do not see a code display above, please enable the display of images in your email program or try accessing it <a href="%1">directly</a>. You may want to take a screen grab of your QR Code in case you need to display it when you do not have Internet access.</div>', [
           1 => $link,
         ]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$values[$contact_id]['qrcodecheckin.qrcode_url_' . $event_id] = $link;
$values[$contact_id]['qrcodecheckin.qrcode_html_' . $event_id] = E::ts('<div><img alt="QR Code with link to checkin page" src="%1"></div><div>You should see a QR code above which will be used to quickly check you into the event. If you do not see a code display above, please enable the display of images in your email program or try accessing it <a href="%1">directly</a>. You may want to take a screen grab of your QR Code in case you need to display it when you do not have Internet access.</div>', [
1 => $link,
]);
$values[$contactId]['qrcodecheckin.qrcode_url_' . $eventId] = $link;
$values[$contactId]['qrcodecheckin.qrcode_html_' . $eventId] = E::ts(
'<div><img alt="QR Code with link to checkin page" src="%1"></div>'
. '<div>You should see a QR code above which will be used to quickly check you into the event. '
. 'If you do not see a code display above, please enable the display of images in your email program '
. 'or try accessing it <a href="%1">directly</a>. You may want to take a screen grab of your QR Code '
. 'in case you need to display it when you do not have Internet access.</div>',
[
1 => $link,
]
);
🤖 Prompt for AI Agents
In
wp-content/civi-extensions/civiglific/api/v3/Civiglific/CivicrmGlificSendWhatsappQrCron.php
around lines 56 to 59, the variable $contact_id is used but not defined; replace
all instances of $contact_id with the correctly defined variable $contactId from
line 39 to fix the undefined variable error.

}
Comment on lines +56 to +60

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unused token value assignments

The code populates $values array with QR code URLs and HTML, but these values are never used in the function. This appears to be copy-pasted from the token generation code without purpose.

If the QR code URL needs to be sent via WhatsApp, pass it as a parameter to the flow. Otherwise, remove these unused assignments:

-        $values[$contactId]['qrcodecheckin.qrcode_url_' . $eventId] = $link;
-        $values[$contactId]['qrcodecheckin.qrcode_html_' . $eventId] = E::ts('<div><img alt="QR Code with link to checkin page" src="%1"></div><div>You should see a QR code above which will be used to quickly check you into the event. If you do not see a code display above, please enable the display of images in your email program or try accessing it <a href="%1">directly</a>. You may want to take a screen grab of your QR Code in case you need to display it when you do not have Internet access.</div>', [
-          1 => $link,
-        ]);
+        // Store the QR code link if needed for the WhatsApp flow
+        $qrCodeLink = $link;

Then pass the QR code link to the flow if needed:

         // Trigger the Flow instead of sending a direct message.
         // Replace with your Flow name.
         $flowName = "TestFlow";
-        $result = triggerFlow($glificClient, $glificContactId, $flowName);
+        // Pass QR code link as flow parameter if needed
+        $result = triggerFlow($glificClient, $glificContactId, $flowName, ['qrCodeUrl' => $qrCodeLink]);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
wp-content/civi-extensions/civiglific/api/v3/Civiglific/CivicrmGlificSendWhatsappQrCron.php
around lines 56 to 60, the $values array is assigned QR code URLs and HTML that
are never used in the function. Remove these unused assignments to clean up the
code. If the QR code URL is required for sending via WhatsApp, instead pass it
explicitly as a parameter to the flow where it is needed.


error_log('testing: Processing participant with contactId: ' . $contactId);

$glificContactId = getGlificContactId($contactId);
error_log('testing: Retrieved glificContactId: ' . $glificContactId);

if (empty($glificContactId)) {
CRM_Core_Error::debug_log_message("No Glific contact ID found for CiviCRM contact ID: $contactId");
error_log('testing: Skipping due to empty glificContactId for contactId: ' . $contactId);
continue;
}

// Trigger the Flow instead of sending a direct message.
// Replace with your Flow name.
$flowName = "TestFlow";
$result = triggerFlow($glificClient, $glificContactId, $flowName);
error_log('testing: Trigger flow result: ' . print_r($result, TRUE));

if ($result['success']) {
$returnValues[] = "Flow triggered for contact ID: $contactId";
}
else {
CRM_Core_Error::debug_log_message("Failed to trigger flow for contact ID: $contactId - " . print_r($result, FALSE));
error_log('testing: Failed to trigger flow for contactId: ' . $contactId);
}
}

error_log('testing: Returning success with returnValues: ' . print_r($returnValues, TRUE));
return civicrm_api3_create_success($returnValues, $params, 'Civiglific', 'civicrm_glific_send_whatsapp_qr_cron');
}
catch (Exception $e) {
CRM_Core_Error::debug_log_message("Error in trigger_flow job: " . $e->getMessage());
error_log('testing: Caught exception: ' . $e->getMessage());
return civicrm_api3_create_error("An error occurred: " . $e->getMessage());
}
}

// /**
// * Fetch participant_id from contact_id.
// */
// function qrcodecheckin_participant_id_for_contact_id($contact_id, $event_id) {

// $sql = "SELECT p.id FROM civicrm_contact c JOIN civicrm_participant p
// ON c.id = p.contact_id WHERE c.is_deleted = 0 AND c.id = %0 AND p.event_id = %1";
// $params = [
// 0 => [$contact_id, 'Integer'],
// 1 => [$event_id, 'Integer'],
// ];
// $dao = CRM_Core_DAO::executeQuery($sql, $params);
// if ($dao->N == 0) {
// return NULL;
// }
// $dao->fetch();
// return $dao->id;
// }

/**
* Create a hash based on the participant id.
*/
// function qrcodecheckin_get_code($participant_id) {
// $sql = "SELECT hash FROM civicrm_contact c JOIN civicrm_participant p ON c.id = p.contact_id
// WHERE p.id = %0";
// $dao = CRM_Core_DAO::executeQuery($sql, [0 => [$participant_id, 'Integer']]);
// if ($dao->N == 0) {
// return FALSE;
// }
// $dao->fetch();
// $user_hash = $dao->hash;
// return hash('sha256', $participant_id . $user_hash . CIVICRM_SITE_KEY);
// }

/**
* Create the qr image file
*/
// function qrcodecheckin_create_image($code, $participant_id) {
// $path = qrcodecheckin_get_path($code);
// if (!file_exists($path)) {
// // Since we are saving a file, we don't want base64 data.
// $url = qrcodecheckin_get_url($code, $participant_id);
// $base64 = FALSE;
// $data = qrcodecheckin_get_image_data($url, $base64);
// file_put_contents($path, $data);
// }
// }

/**
* Helper to return absolute URL to qrcode image file.
*
* This is the URL to the image file containing the QR code.
*/
// function qrcodecheckin_get_image_url($code) {
// $civiConfig = CRM_Core_Config::singleton();
// return $civiConfig->imageUploadURL . '/qrcodecheckin/' . $code . '.png';
// }


/**
* Get QRCode image data.
*/
// function qrcodecheckin_get_image_data($url, $base64 = TRUE) {
// require_once __DIR__ . '/vendor/autoload.php';
// $options = new chillerlan\QRCode\QROptions(
// [
// 'outputType' => chillerlan\QRCode\QRCode::OUTPUT_IMAGE_PNG,
// 'imageBase64' => $base64,
// 'imageTransparent' => FALSE,
// ]
// );
// return (new chillerlan\QRCode\QRCode($options))->render($url);
// }

/**
* Get URL for checkin.
*
* This is the URL that the QR Code points to when it is
* read. See qrcodecheckin_get_image_url for the URL of the image
* file that displays the QR Code.
*/
// function qrcodecheckin_get_url($code, $participant_id) {
// $query = NULL;
// $absolute = TRUE;
// $fragment = NULL;
// $htmlize = FALSE;
// $frontend = TRUE;
// return CRM_Utils_System::url('civicrm/qrcodecheckin/' . $participant_id . '/' . $code, $query, $absolute, $fragment, $htmlize, $frontend);
// }


/**
* Helper to return absolute file system path to qrcode image file.
*
* This is the path to the image file containing the QR code.
*/
// function qrcodecheckin_get_path($code) {
// $civiConfig = CRM_Core_Config::singleton();
// return $civiConfig->imageUploadDir . '/qrcodecheckin/' . $code . '.png';
// }

Comment on lines +98 to +198

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove commented-out code blocks

Large sections of commented-out code should be removed. These functions appear to be duplicates of the qrcodecheckin extension functions and serve no purpose here.

Delete all the commented-out function implementations from lines 98-198. Version control preserves the history if needed.

🤖 Prompt for AI Agents
In
wp-content/civi-extensions/civiglific/api/v3/Civiglific/CivicrmGlificSendWhatsappQrCron.php
from lines 98 to 198, remove all the commented-out function implementations as
they are redundant duplicates of the qrcodecheckin extension functions and serve
no purpose here. Since version control retains history, deleting these commented
blocks will clean up the code without losing information.



/**
* Retrieve Glific contact ID dynamically using phone number.
*
* @param int $contactId
* CiviCRM contact ID.
*
* @return string|null
* Glific contact ID or null if not found.
*/
function getGlificContactId($contactId) {
error_log('testing: Entering getGlificContactId for contactId: ' . $contactId);
$phoneResult = Phone::get(FALSE)
->addSelect('phone')
->addWhere('contact_id', '=', $contactId)
->execute()
->first();
error_log('testing: Phone result: ' . print_r($phoneResult, TRUE));

if (empty($phoneResult['phone'])) {
error_log('testing: No phone found for contactId: ' . $contactId);
return NULL;
}

$phone = $phoneResult['phone'];
$glificClient = new GlificClient();
error_log('testing: Querying Glific for phone: ' . $phone);

return $glificClient->getContactIdByPhone($phone);
}

/**
* Trigger a Flow for a specific contact using Glific API.
*
* @param \CRM\Civiglific\GlificClient $client
* GlificClient instance.
* @param string $receiverId
* Glific contact ID of the receiver.
* @param string $flowName
* Name of the Flow to trigger.
*
* @return array
* Response with success status.
*/
function triggerFlow($client, $receiverId, $flowName) {
error_log('testing: Entering triggerFlow with receiverId: ' . $receiverId . ' and flowName: ' . $flowName);
$query = <<<'GQL'
mutation TriggerContactFlow($input: TriggerContactFlowInput!) {
triggerContactFlow(input: $input) {
flow {
id
name
}
errors {
message
}
}
}
GQL;

$variables = [
'input' => [
'contactId' => $receiverId,
'flowName' => $flowName,
],
];
error_log('testing: Trigger flow variables: ' . print_r($variables, TRUE));

$response = $client->query($query, $variables);
error_log('testing: Trigger flow response: ' . print_r($response, TRUE));

$result = $response['data']['triggerContactFlow'] ?? [];
$success = empty($result['errors']);
return [
'success' => $success,
'data' => $result,
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/**
* Class CRM_Qrcodecheckin_Hook
*
* This class implements hooks for Qrcodecheckin
*/
class CRM_Qrcodecheckin_Hook {

/**
* This hook allows to alter qrcodecheckin tokens.
*
* @param array $values Array of token values for current contactId
* @param int $contactId
* @param bool $handled - Set to TRUE if your hook handled the token values, FALSE to allow default handling
*
* @return mixed
*/
public static function tokenValues(&$values, $contactId, &$handled) {
return CRM_Utils_Hook::singleton()
->invoke(['values', 'contactId', 'handled'], $values, $contactId, $handled, CRM_Utils_Hook::$_nullObject,
CRM_Utils_Hook::$_nullObject, CRM_Utils_Hook::$_nullObject, 'civicrm_qrcodecheckin_tokenValues');
}

}
Loading