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

Material contibution #354

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

belwalshubham
Copy link
Collaborator

@belwalshubham belwalshubham commented Oct 10, 2024

Description

Summary by CodeRabbit

  • New Features

    • Introduced a new QR code generation service for collection camps, enhancing event handling and data integrity.
    • Expanded data retrieval capabilities for dropping centers, including new fields for start time, end time, and address.
  • Bug Fixes

    • Improved error handling for date processing in configuration settings, ensuring more user-friendly error messages.
  • Refactor

    • Streamlined configuration handling for target types, improving modularity and maintainability of the code.

Copy link

coderabbitai bot commented Oct 10, 2024

Walkthrough

The pull request introduces significant enhancements to the CollectionCampService and QrCodeService classes within the Civi namespace, focusing on QR code generation and event handling. Key changes include the addition of a new QrCodeService class for centralized QR code generation, modifications to existing methods in CollectionCampService to incorporate a new parameter for collection camp subtype, and a restructuring of configuration handling in the render.php files of the Goonj Blocks plugin. These updates aim to streamline functionality and improve data handling.

Changes

File Path Change Summary
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php - Updated method signatures for generateCollectionCampQr and reGenerateCollectionCampQr to include $collectionCampSubtype.
- Modified methods to log subtype data and ensure it is retrieved correctly.
- Added createCollectionCampOrganizeActivity method.
wp-content/civi-extensions/goonjcustom/Civi/QrCodeService.php - Added QrCodeService class with methods for generating QR codes.
- Introduced constants for URL patterns and implemented error handling for QR code generation and attachment saving.
wp-content/plugins/goonj-blocks/build/render.php - Created a new $target_config array for handling configurations of 'collection-camp' and 'dropping-center'.
- Updated control flow to streamline configuration retrieval and added error handling for date parsing.
wp-content/plugins/goonj-blocks/goonj-blocks.php - Added new fields to $entity_fields for 'dropping-center' target to enhance data retrieval capabilities.
wp-content/plugins/goonj-blocks/src/render.php - Similar modifications as in build/render.php, focusing on target configuration handling and error management for date creation.

Possibly related PRs

  • Refactor: Store entity ID in Eck_Collection_Camp1 in directive #307: This PR modifies the CollectionCampService class, which is directly related to the changes in the main PR that also focuses on the CollectionCampService class, particularly in enhancing its functionalities.
  • bug fixes and refactor #329: This PR introduces new methods in the CollectionCampService class for sending logistics emails and updating contributor counts, which aligns with the main PR's focus on enhancing the CollectionCampService functionalities related to event handling and notifications.

Suggested labels

in review

Suggested reviewers

  • pokhiii

🌟 In the realm of code, where logic does flow,
New features emerge, like a bright, shining glow.
QR codes now dance with a subtype in tow,
Goonj Blocks are ready, with configurations to show!
Error handling's here, making sure all is right,
As we celebrate changes, let's code through the night! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@belwalshubham belwalshubham changed the title Remove afform.validate hook Remove Custom Validation Oct 10, 2024
@belwalshubham belwalshubham changed the title Remove Custom Validation Material contibution Oct 10, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Outside diff range and nitpick comments (5)
wp-content/plugins/goonj-blocks/goonj-blocks.php (2)

91-93: Approved: New fields added to $entity_fields array

The addition of these new fields for the Dropping Centre entity enhances the data retrieval capabilities of the plugin. This change aligns well with the function's purpose and doesn't introduce any violations of software development best practices.

However, to improve code readability and maintainability, consider grouping related fields together. You could reorganize the $entity_fields array to keep all Dropping Centre fields adjacent to each other.

Here's a suggestion for improved organization:

$entity_fields = array(
    'id',
    'title',
    'Collection_Camp_Intent_Details.Start_Date',
    'Collection_Camp_Intent_Details.End_Date',
    'Collection_Camp_Intent_Details.Location_Area_of_camp',
    'Collection_Camp_Intent_Details.City',
    'Collection_Camp_Intent_Details.State',
    'Dropping_Centre.Start_Time',
    'Dropping_Centre.End_Time',
    'Dropping_Centre.Where_do_you_wish_to_open_dropping_center_Address_',
);

This organization makes it easier to identify and manage fields related to specific entities.


Line range hint 46-155: Suggestion: Refactor gb_goonj_blocks_check_action_target_exists for improved organization

While the current implementation works, there are opportunities to improve code organization and reduce duplication:

  1. The function gb_goonj_blocks_check_action_target_exists is handling multiple responsibilities. Consider breaking it down into smaller, more focused functions.

  2. There's code duplication in the switch statement for 'collection-camp' and 'dropping-center' cases. These could be combined into a single case with a shared logic.

  3. The error handling (404 response) is repeated. This could be extracted into a separate function for reusability.

Here's a high-level suggestion for refactoring:

function gb_goonj_blocks_check_action_target_exists() {
    if (!should_process_action()) {
        return;
    }

    $target = get_query_var('target');
    $id = intval(get_query_var('id'));

    load_civicrm();

    $action_target = get_action_target($target, $id);

    if ($action_target === false) {
        handle_404();
    } else {
        global $wp_query;
        $wp_query->set('action_target', $action_target);
    }
}

function should_process_action() {
    return is_page('actions') && get_query_var('target') && get_query_var('id');
}

function load_civicrm() {
    if (function_exists('civicrm_initialize')) {
        civicrm_initialize();
    }
}

function get_action_target($target, $id) {
    switch ($target) {
        case 'collection-camp':
        case 'dropping-center':
            return get_collection_camp_or_dropping_center($id);
        case 'processing-center':
            return get_processing_center($id);
        default:
            return false;
    }
}

function handle_404() {
    global $wp_query;
    $wp_query->set_404();
    status_header(404);
    nocache_headers();
    include get_query_template('404');
    exit;
}

// Implement get_collection_camp_or_dropping_center and get_processing_center functions

This refactoring improves code organization, reduces duplication, and makes the code more maintainable and testable.

wp-content/civi-extensions/goonjcustom/Civi/QrCodeService.php (2)

58-61: Enhance Error Handling for File Write Failures

Currently, if file_put_contents fails, it logs the error but continues execution. This could lead to further errors down the line.

Consider throwing an exception or returning early to handle the failure appropriately.

Adjust the code as follows:

if (!$numBytes) {
  \CRM_Core_Error::debug_log_message('Failed to write QR code to temporary file for collection camp ID ' . $collectionCampId);
+ throw new \Exception('Failed to write QR code to temporary file.');
}

This ensures that the failure is caught in the catch block, and the method exits gracefully.


101-104: Catch More Specific Exceptions

Catching the base \Exception class may mask more specific exceptions that could be handled differently.

Consider catching specific exceptions or using \Throwable to catch all errors:

- catch (\Exception $e) {
+ catch (\Throwable $e) {
  \CRM_Core_Error::debug_log_message('Error generating QR code: ' . $e->getMessage());
  return FALSE;
}

Additionally, include the stack trace for more detailed logging:

\CRM_Core_Error::debug_log_message('Error generating QR code: ' . $e->getMessage() . PHP_EOL . $e->getTraceAsString());
wp-content/plugins/goonj-blocks/build/render.php (1)

99-99: Verify consistency in action button styling and labeling

The addition of the "Record your Material Contribution" button is appropriate. Ensure that its styling and labeling are consistent with other action buttons to maintain a cohesive user interface.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 5033b74 and 550660f.

📒 Files selected for processing (5)
  • wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (4 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/QrCodeService.php (1 hunks)
  • wp-content/plugins/goonj-blocks/build/render.php (2 hunks)
  • wp-content/plugins/goonj-blocks/goonj-blocks.php (1 hunks)
  • wp-content/plugins/goonj-blocks/src/render.php (2 hunks)
🧰 Additional context used
📓 Learnings (4)
📓 Common learnings
Learnt from: belwalshubham
PR: ColoredCow/goonj#284
File: wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php:520-520
Timestamp: 2024-10-08T09:24:47.239Z
Learning: In `wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php`, it's acceptable that the `reGenerateCollectionCampQr` method calls `generateQrCode` with only the `$collectionCampId` parameter, as QR codes are generated when the Dropping Center is authorized. We'll implement changes if any issues arise in the future.
Learnt from: belwalshubham
PR: ColoredCow/goonj#284
File: wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php:520-520
Timestamp: 2024-10-09T05:09:48.296Z
Learning: In `wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php`, it's acceptable that the `reGenerateCollectionCampQr` method calls `generateQrCode` with only the `$collectionCampId` parameter, as QR codes are generated when the Dropping Center is authorized. We'll implement changes if any issues arise in the future.
wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php (2)
Learnt from: belwalshubham
PR: ColoredCow/goonj#284
File: wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php:520-520
Timestamp: 2024-10-08T09:24:47.239Z
Learning: In `wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php`, it's acceptable that the `reGenerateCollectionCampQr` method calls `generateQrCode` with only the `$collectionCampId` parameter, as QR codes are generated when the Dropping Center is authorized. We'll implement changes if any issues arise in the future.
Learnt from: belwalshubham
PR: ColoredCow/goonj#284
File: wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php:520-520
Timestamp: 2024-10-09T05:09:48.296Z
Learning: In `wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php`, it's acceptable that the `reGenerateCollectionCampQr` method calls `generateQrCode` with only the `$collectionCampId` parameter, as QR codes are generated when the Dropping Center is authorized. We'll implement changes if any issues arise in the future.
wp-content/civi-extensions/goonjcustom/Civi/QrCodeService.php (2)
Learnt from: belwalshubham
PR: ColoredCow/goonj#284
File: wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php:520-520
Timestamp: 2024-10-08T09:24:47.239Z
Learning: In `wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php`, it's acceptable that the `reGenerateCollectionCampQr` method calls `generateQrCode` with only the `$collectionCampId` parameter, as QR codes are generated when the Dropping Center is authorized. We'll implement changes if any issues arise in the future.
Learnt from: belwalshubham
PR: ColoredCow/goonj#284
File: wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php:520-520
Timestamp: 2024-10-09T05:09:48.296Z
Learning: In `wp-content/civi-extensions/goonjcustom/Civi/CollectionCampService.php`, it's acceptable that the `reGenerateCollectionCampQr` method calls `generateQrCode` with only the `$collectionCampId` parameter, as QR codes are generated when the Dropping Center is authorized. We'll implement changes if any issues arise in the future.
wp-content/plugins/goonj-blocks/src/render.php (1)
Learnt from: belwalshubham
PR: ColoredCow/goonj#284
File: wp-content/plugins/goonj-blocks/src/render.php:45-47
Timestamp: 2024-10-08T09:25:18.536Z
Learning: In the `wp-content/plugins/goonj-blocks/src/render.php` file, the team considers error handling for `DateTime` object creation unnecessary when using `$action_target['Dropping_Centre.Start_Time']` and `$action_target['Dropping_Centre.End_Time']`.
🔇 Additional comments (2)
wp-content/civi-extensions/goonjcustom/Civi/QrCodeService.php (1)

48-50: ⚠️ Potential issue

Incorrect Handling of QR Code Data

When using QRCode::OUTPUT_IMAGE_PNG, the render method returns binary image data, not a base64-encoded string with a data URI prefix. The current code performs str_replace and base64_decode, which can corrupt the image data.

Verify and adjust the handling of $qrcode:

Run the following script to confirm the output of QRCode::render:

Suggested Fix:

Remove the unnecessary data manipulation:

- // Remove the base64 header and decode the image data.
- $qrcode = str_replace('data:image/png;base64,', '', $qrcode);
- $qrcode = base64_decode($qrcode);

The $qrcode variable should already contain the correct binary data suitable for writing directly to a file.

wp-content/plugins/goonj-blocks/build/render.php (1)

48-61: Great use of configuration array for target types

Consolidating the configuration data into the $target_config array enhances readability and makes it easier to manage settings for different target types.

/**
*
*/
class QrCodeService extends AutoSubscriber {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Unnecessary Extension of AutoSubscriber

The QrCodeService class extends AutoSubscriber, but the getSubscribedEvents() method returns an empty array. Since the class isn't subscribing to any events, consider removing the extension to adhere to the Single Responsibility Principle and eliminate unnecessary inheritance.

Comment on lines +28 to +107
public static function generateQrCode($collectionCampId, $collectionCampSubtype) {
try {
$baseUrl = \CRM_Core_Config::singleton()->userFrameworkBaseURL;

if ($collectionCampSubtype === 'Dropping_Center') {
$url = sprintf(self::DROPPING_CENTER_URL_PATTERN, $baseUrl, $collectionCampId);
}
else {
$url = sprintf(self::COLLECTION_CAMP_URL_PATTERN, $baseUrl, $collectionCampId);
}

$options = new QROptions([
'version' => 5,
'outputType' => QRCode::OUTPUT_IMAGE_PNG,
'eccLevel' => QRCode::ECC_L,
'scale' => 10,
]);

$qrcode = (new QRCode($options))->render($url);

// Remove the base64 header and decode the image data.
$qrcode = str_replace('data:image/png;base64,', '', $qrcode);
$qrcode = base64_decode($qrcode);

$baseFileName = "qr_code_{$collectionCampId}.png";
$fileName = \CRM_Utils_File::makeFileName($baseFileName);
$tempFilePath = \CRM_Utils_File::tempnam($baseFileName);

$numBytes = file_put_contents($tempFilePath, $qrcode);

if (!$numBytes) {
\CRM_Core_Error::debug_log_message('Failed to write QR code to temporary file for collection camp ID ' . $collectionCampId);
return FALSE;
}

$customFields = CustomField::get(FALSE)
->addSelect('id')
->addWhere('custom_group_id:name', '=', 'Collection_Camp_QR_Code')
->addWhere('name', '=', 'QR_Code')
->setLimit(1)
->execute();

$qrField = $customFields->first();

if (!$qrField) {
\CRM_Core_Error::debug_log_message('No field to save QR Code for collection camp ID ' . $collectionCampId);
return FALSE;
}

$qrFieldId = 'custom_' . $qrField['id'];

// Save the QR code as an attachment linked to the collection camp.
$params = [
'entity_id' => $collectionCampId,
'name' => $fileName,
'mime_type' => 'image/png',
'field_name' => $qrFieldId,
'options' => [
'move-file' => $tempFilePath,
],
];

$result = civicrm_api3('Attachment', 'create', $params);

if (!empty($result['is_error'])) {
\CRM_Core_Error::debug_log_message('Failed to create attachment for collection camp ID ' . $collectionCampId);
return FALSE;
}

$attachment = $result['values'][$result['id']];
$attachmentUrl = $attachment['url'];

}
catch (\Exception $e) {
\CRM_Core_Error::debug_log_message('Error generating QR code: ' . $e->getMessage());
return FALSE;
}

return TRUE;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Method generateQrCode Violates Single Responsibility Principle

The generateQrCode method is handling multiple responsibilities:

  • Generating the QR code.
  • Handling file operations (writing to a temp file).
  • Interacting with the database to retrieve custom fields.
  • Creating an attachment via the CiviCRM API.

Consider refactoring this method into smaller, dedicated methods for each responsibility. This will enhance readability, maintainability, and testability of the code.

Refactoring suggestions:

  • Extract QR Code Generation:

    private static function createQrCode($url) {
      $options = new QROptions([
        'version'    => 5,
        'outputType' => QRCode::OUTPUT_IMAGE_PNG,
        'eccLevel'   => QRCode::ECC_L,
        'scale'      => 10,
      ]);
    
      return (new QRCode($options))->render($url);
    }
  • Extract File Handling:

    private static function saveQrCodeToFile($qrcodeData, $collectionCampId) {
      $baseFileName = "qr_code_{$collectionCampId}.png";
      $fileName = \CRM_Utils_File::makeFileName($baseFileName);
      $tempFilePath = \CRM_Utils_File::tempnam($baseFileName);
    
      $numBytes = file_put_contents($tempFilePath, $qrcodeData);
    
      if (!$numBytes) {
        \CRM_Core_Error::debug_log_message('Failed to write QR code to temporary file for collection camp ID ' . $collectionCampId);
        return FALSE;
      }
    
      return ['tempFilePath' => $tempFilePath, 'fileName' => $fileName];
    }
  • Extract Custom Field Retrieval:

    private static function getQrCodeCustomFieldId() {
      $customFields = CustomField::get(FALSE)
        ->addSelect('id')
        ->addWhere('custom_group_id:name', '=', 'Collection_Camp_QR_Code')
        ->addWhere('name', '=', 'QR_Code')
        ->setLimit(1)
        ->execute();
    
      $qrField = $customFields->first();
    
      if (!$qrField) {
        return FALSE;
      }
    
      return 'custom_' . $qrField['id'];
    }
  • Extract Attachment Creation:

    private static function attachQrCodeToCollectionCamp($collectionCampId, $fileName, $tempFilePath, $qrFieldId) {
      $params = [
        'entity_id' => $collectionCampId,
        'name' => $fileName,
        'mime_type' => 'image/png',
        'field_name' => $qrFieldId,
        'options' => [
          'move-file' => $tempFilePath,
        ],
      ];
    
      $result = civicrm_api3('Attachment', 'create', $params);
    
      if (!empty($result['is_error'])) {
        \CRM_Core_Error::debug_log_message('Failed to create attachment for collection camp ID ' . $collectionCampId . '. Error: ' . $result['error_message']);
        return FALSE;
      }
    
      return TRUE;
    }

By breaking down the method, each part becomes more modular and easier to maintain.

Comment on lines +92 to +95
if (!empty($result['is_error'])) {
\CRM_Core_Error::debug_log_message('Failed to create attachment for collection camp ID ' . $collectionCampId);
return FALSE;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve Error Logging for API Failures

When the API call to create the attachment fails, the error message lacks specific details.

Modify the error logging to include the API error message:

if (!empty($result['is_error'])) {
- \CRM_Core_Error::debug_log_message('Failed to create attachment for collection camp ID ' . $collectionCampId);
+ \CRM_Core_Error::debug_log_message('Failed to create attachment for collection camp ID ' . $collectionCampId . '. Error: ' . $result['error_message']);
  return FALSE;
}

This provides clearer insight into the cause of the failure, aiding in faster debugging.

📝 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
if (!empty($result['is_error'])) {
\CRM_Core_Error::debug_log_message('Failed to create attachment for collection camp ID ' . $collectionCampId);
return FALSE;
}
if (!empty($result['is_error'])) {
\CRM_Core_Error::debug_log_message('Failed to create attachment for collection camp ID ' . $collectionCampId . '. Error: ' . $result['error_message']);
return FALSE;
}

Comment on lines +42 to +46
$dropping_center_material_contribution_link = sprintf(
'/dropping-center-contribution?source=%s&target_id=%s',
$action_target['title'],
$action_target['id'],
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor link generation to eliminate duplicate code

The link generation for 'dropping-center' and 'collection-camp' shares similar structures. To adhere to the DRY (Don't Repeat Yourself) principle and enhance maintainability, consider abstracting this logic into a reusable function.

You can create a function like this:

function generate_contribution_link($type, $action_target) {
    if ($type === 'collection-camp') {
        return sprintf(
            '/collection-camp-contribution?source=%s&target_id=%s&state_province_id=%s&city=%s',
            $action_target['title'],
            $action_target['id'],
            $action_target['Collection_Camp_Intent_Details.State'],
            $action_target['Collection_Camp_Intent_Details.City'],
        );
    } elseif ($type === 'dropping-center') {
        return sprintf(
            '/dropping-center-contribution?source=%s&target_id=%s',
            $action_target['title'],
            $action_target['id'],
        );
    }
    return '';
}

Then, update the assignments:

-$material_contribution_link = sprintf(
-    '/collection-camp-contribution?source=%s&target_id=%s&state_province_id=%s&city=%s',
-    $action_target['title'],
-    $action_target['id'],
-    $action_target['Collection_Camp_Intent_Details.State'],
-    $action_target['Collection_Camp_Intent_Details.City'],
-);
-
-$dropping_center_material_contribution_link = sprintf(
-    '/dropping-center-contribution?source=%s&target_id=%s',
-    $action_target['title'],
-    $action_target['id'],
-);
+ $contribution_link = generate_contribution_link($target, $action_target);

And adjust the $target_config accordingly.

Comment on lines +62 to +74
if (isset($target_config[$target])) :
try {
$config = $target_config[$target];
$start_date = new DateTime($action_target[$config['start_time']]);
$end_date = new DateTime($action_target[$config['end_time']]);
$address = $action_target[$config['address']];
$contribution_link = $config['contribution_link'];
}
catch (Exception $e) {
\Civi::log()->error('Invalid date format for start or end time', ['error' => $e->getMessage(), 'target' => $target]);
echo '<div class="error">An error occurred. Please try again later.</div>';
return;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve exception handling to protect sensitive information

While the try-catch block effectively handles exceptions, logging the error message may expose sensitive information. Consider logging only essential details and providing a user-friendly message.

Apply this change to safeguard sensitive data:

catch (Exception $e) {
-  \Civi::log()->error('Invalid date format for start or end time', ['error' => $e->getMessage(), 'target' => $target]);
+  \Civi::log()->error('Invalid date format for start or end time', ['target' => $target]);
   echo '<div class="error">An error occurred. Please try again later.</div>';
   return;
}

This modification ensures that detailed exception messages aren't exposed, aligning with best security practices.

📝 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
if (isset($target_config[$target])) :
try {
$config = $target_config[$target];
$start_date = new DateTime($action_target[$config['start_time']]);
$end_date = new DateTime($action_target[$config['end_time']]);
$address = $action_target[$config['address']];
$contribution_link = $config['contribution_link'];
}
catch (Exception $e) {
\Civi::log()->error('Invalid date format for start or end time', ['error' => $e->getMessage(), 'target' => $target]);
echo '<div class="error">An error occurred. Please try again later.</div>';
return;
}
if (isset($target_config[$target])) :
try {
$config = $target_config[$target];
$start_date = new DateTime($action_target[$config['start_time']]);
$end_date = new DateTime($action_target[$config['end_time']]);
$address = $action_target[$config['address']];
$contribution_link = $config['contribution_link'];
}
catch (Exception $e) {
\Civi::log()->error('Invalid date format for start or end time', ['target' => $target]);
echo '<div class="error">An error occurred. Please try again later.</div>';
return;
}

Comment on lines +63 to +74
try {
$config = $target_config[$target];
$start_date = new DateTime($action_target[$config['start_time']]);
$end_date = new DateTime($action_target[$config['end_time']]);
$address = $action_target[$config['address']];
$contribution_link = $config['contribution_link'];
}
catch (Exception $e) {
\Civi::log()->error('Invalid date format for start or end time', ['error' => $e->getMessage(), 'target' => $target]);
echo '<div class="error">An error occurred. Please try again later.</div>';
return;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unnecessary error handling around DateTime creation

Previous team discussions concluded that error handling for DateTime object creation is unnecessary when using $action_target data. The try-catch block may be redundant, as the dates are expected to be valid. Removing it simplifies the code and aligns with team conventions.

Apply this diff to remove the try-catch block:

-if (isset($target_config[$target])) :
-  try {
     $config = $target_config[$target];
     $start_date = new DateTime($action_target[$config['start_time']]);
     $end_date = new DateTime($action_target[$config['end_time']]);
     $address = $action_target[$config['address']];
     $contribution_link = $config['contribution_link'];
-  }
-  catch (Exception $e) {
-    \Civi::log()->error('Invalid date format for start or end time', ['error' => $e->getMessage(), 'target' => $target]);
-    echo '<div class="error">An error occurred. Please try again later.</div>';
-    return;
-  }	
+if (isset($target_config[$target])) :
+  $config = $target_config[$target];
+  $start_date = new DateTime($action_target[$config['start_time']]);
+  $end_date = new DateTime($action_target[$config['end_time']]);
+  $address = $action_target[$config['address']];
+  $contribution_link = $config['contribution_link'];

This change removes the unnecessary error handling, streamlining the code.

Committable suggestion was skipped due to low confidence.

Comment on lines +48 to +61
$target_config = [
'dropping-center' => [
'start_time' => 'Dropping_Centre.Start_Time',
'end_time' => 'Dropping_Centre.End_Time',
'address' => 'Dropping_Centre.Where_do_you_wish_to_open_dropping_center_Address_',
'contribution_link' => $dropping_center_material_contribution_link,
],
'collection-camp' => [
'start_time' => 'Collection_Camp_Intent_Details.Start_Date',
'end_time' => 'Collection_Camp_Intent_Details.End_Date',
'address' => 'Collection_Camp_Intent_Details.Location_Area_of_camp',
'contribution_link' => $material_contribution_link,
],
];
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider including 'processing-center' in $target_config to reduce code duplication

The current implementation handles 'dropping-center' and 'collection-camp' using the $target_config array, but 'processing-center' is handled separately. To adhere to the DRY (Don't Repeat Yourself) principle and enhance maintainability, consider adding 'processing-center' to $target_config. This unifies the logic and simplifies future extensions.

Here's a suggested change:

     ],
     'collection-camp' => [
       'start_time' => 'Collection_Camp_Intent_Details.Start_Date',
       'end_time' => 'Collection_Camp_Intent_Details.End_Date',
       'address' => 'Collection_Camp_Intent_Details.Location_Area_of_camp',
       'contribution_link' => $material_contribution_link,
     ],
+    'processing-center' => [
+      'address' => $action_target['address'],
+      'visit_link' => $pu_visit_check_link,
+      'contribution_link' => $pu_material_contribution_check_link,
+    ],
   ];

Adjust the subsequent code to utilize the $config array for 'processing-center' as well. This might include handling the absence of start and end dates for 'processing-center' or adding default values where necessary.

Committable suggestion was skipped due to low confidence.

Comment on lines +547 to +552
$collectionCampSubtype = $collectionCamp['subtype:name'];

if (empty($collectionCampSubtype)) {
\Civi::log()->error('Collection camp subtype is not set or is empty for Collection Camp ID: ' . $collectionCampId);
return;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Eliminate code duplication by using a helper method

The code in lines 547-552 duplicates the logic for retrieving and checking $collectionCampSubtype. Refactoring this into a shared private method will enhance code readability and simplify maintenance.

Update the reGenerateCollectionCampQr method:

-     $collectionCampSubtype = $collectionCamp['subtype:name'];
-
-     if (empty($collectionCampSubtype)) {
-         \Civi::log()->error('Collection camp subtype is not set or is empty for Collection Camp ID: ' . $collectionCampId);
-         return;
-     }
+     $collectionCampSubtype = self::getCollectionCampSubtype($collectionCampId);
+     if ($collectionCampSubtype === null) {
+         return;
+     }

Ensure that the new helper method handles logging appropriately based on the context (e.g., use different log levels if necessary).

Committable suggestion was skipped due to low confidence.

Comment on lines +505 to +510
$collectionCampSubtype = $currentCollectionCamp['subtype:name'];

if (empty($collectionCampSubtype)) {
\Civi::log()->warning('Collection camp subtype is not set or is empty for Collection Camp ID: ' . $collectionCampId);
return;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor duplicated code for handling $collectionCampSubtype

The logic in lines 505-510 for retrieving and validating $collectionCampSubtype is duplicated in the reGenerateCollectionCampQr method (lines 547-552). To adhere to the DRY (Don't Repeat Yourself) principle and improve maintainability, consider extracting this code into a reusable private method.

Apply this diff to refactor the duplicated code:

+ private static function getCollectionCampSubtype(int $collectionCampId) {
+     $collectionCamp = EckEntity::get('Collection_Camp', TRUE)
+         ->addSelect('subtype:name')
+         ->addWhere('id', '=', $collectionCampId)
+         ->execute()->single();
+     
+     $collectionCampSubtype = $collectionCamp['subtype:name'];
+     
+     if (empty($collectionCampSubtype)) {
+         \Civi::log()->warning('Collection camp subtype is not set or is empty for Collection Camp ID: ' . $collectionCampId);
+         return null;
+     }
+     
+     return $collectionCampSubtype;
+ }

Then update the generateCollectionCampQr method:

-     $collectionCampSubtype = $currentCollectionCamp['subtype:name'];
-
-     if (empty($collectionCampSubtype)) {
-         \Civi::log()->warning('Collection camp subtype is not set or is empty for Collection Camp ID: ' . $collectionCampId);
-         return;
-     }
+     $collectionCampSubtype = self::getCollectionCampSubtype($collectionCampId);
+     if ($collectionCampSubtype === null) {
+         return;
+     }
📝 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
$collectionCampSubtype = $currentCollectionCamp['subtype:name'];
if (empty($collectionCampSubtype)) {
\Civi::log()->warning('Collection camp subtype is not set or is empty for Collection Camp ID: ' . $collectionCampId);
return;
}
private static function getCollectionCampSubtype(int $collectionCampId) {
$collectionCamp = EckEntity::get('Collection_Camp', TRUE)
->addSelect('subtype:name')
->addWhere('id', '=', $collectionCampId)
->execute()->single();
$collectionCampSubtype = $collectionCamp['subtype:name'];
if (empty($collectionCampSubtype)) {
\Civi::log()->warning('Collection camp subtype is not set or is empty for Collection Camp ID: ' . $collectionCampId);
return null;
}
return $collectionCampSubtype;
}
$collectionCampSubtype = self::getCollectionCampSubtype($collectionCampId);
if ($collectionCampSubtype === null) {
return;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant