Skip to content

institution code cleanups#1005

Merged
belwalshubham merged 3 commits intodevelopfrom
feat/organization-code-cleanups
Feb 19, 2025
Merged

institution code cleanups#1005
belwalshubham merged 3 commits intodevelopfrom
feat/organization-code-cleanups

Conversation

@belwalshubham
Copy link
Copy Markdown
Collaborator

@belwalshubham belwalshubham commented Feb 19, 2025

Summary by CodeRabbit

  • Refactor
    • Updated the retrieval of organization address, email, and phone details across institutional modules to ensure consistent and accurate data in notifications, links, and receipts.
  • New Features
    • Introduced a new command-line tool that automates assigning institutional contact data to the appropriate group for streamlined administrative processes.
    • Updated the existing CLI script to fetch contacts from the 'Institution' group instead of the previous group.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 19, 2025

Walkthrough

This pull request updates the method for retrieving organization address data across multiple components. The field previously referenced as Institute_Registration.Address is now consistently replaced with address_primary.street_address in form classes and service methods. Additional modifications update related email and phone field lookups. A new CLI script is introduced to assign Points of Contact (POCs) for institutions by retrieving and updating organization details. Method signatures and public declarations remain unchanged.

Changes

File(s) Change Summary
wp-content/.../CRM/Goonjcustom/Form/InstitutionCollectionCampLinks.php
wp-content/.../CRM/Goonjcustom/Form/InstitutionDroppingCenterLinks.php
Updated data retrieval logic in form classes: replaced Institute_Registration.Address with address_primary.street_address. In DroppingCenterLinks, email and phone fields were also updated.
wp-content/.../Civi/InstitutionCollectionCampService.php
wp-content/.../Civi/InstitutionDroppingCenterService.php
wp-content/.../Civi/InstitutionMaterialContributionService.php
Modified service methods to fetch the organization address using address_primary.street_address instead of Institute_Registration.Address.
wp-content/.../cli/assign-contact-data.php Introduced a new CLI script that defines getInstituteFromGroup() and assignInstitutePocToInstitute() to retrieve contacts from a group, fetch organization data via API, and assign POC data.
wp-content/.../cli/assign-group-to-individual.php Updated constant SOURCE_GROUP_NAME from 'Opted out List (No Bulk Email)' to 'Institution' to change the group from which contacts are fetched.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI Script
    participant GroupAPI as Group API
    participant OrgAPI as Organization API

    CLI->>GroupAPI: getInstituteFromGroup() 
    GroupAPI-->>CLI: Return list of contacts
    loop For each contact
        CLI->>OrgAPI: Fetch organization details
        OrgAPI-->>CLI: Return organization data
        CLI->>OrgAPI: Update organization with mapped POC fields
        OrgAPI-->>CLI: Confirmation/Error message
    end
    CLI->>CLI: Log completion message
Loading

Possibly related PRs

Suggested labels

status : ready for review

Suggested reviewers

  • nishant22029
  • tarunnjoshi

Poem

In code we twist and turn the line,
Changing fields where data shines.
Old addresses yield to a newer beat,
And a CLI script makes the process complete.
Cheers to clean code—a journey so fine!


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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

Copy link
Copy Markdown

@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: 3

🔭 Outside diff range comments (2)
wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionDroppingCenterLinks.php (1)

108-124: ⚠️ Potential issue

Sanitize URL parameters to prevent XSS.

The URL generation includes user-provided data without proper sanitization, which could lead to XSS attacks.

Consider using urlencode() for all user-provided parameters:

 $links = [
   [
     'label' => 'Vehicle Dispatch',
     'url' => self::createUrl(
       '/institution-dropping-center-vehicle-dispatch',
       "Camp_Vehicle_Dispatch.Institution_Dropping_Center={$this->_institutionDroppingCenterId}" .
       "&Eck_Collection_Camp1={$this->_institutionDroppingCenterId}" .
       "&Camp_Vehicle_Dispatch.To_which_PU_Center_material_is_being_sent={$this->_processingCenterId}" .
       "&Camp_Vehicle_Dispatch.Filled_by={$contactId}" .
-      "&Camp_Institution_Data.Name_of_the_institution={$nameOfInstitution}" .
-      "&Camp_Institution_Data.Address={$address}" .
-      "&Camp_Institution_Data.Email={$pocEmail}" .
-      "&Camp_Institution_Data.Contact_Number={$pocContactNumber}",
+      "&Camp_Institution_Data.Name_of_the_institution=" . urlencode($nameOfInstitution) .
+      "&Camp_Institution_Data.Address=" . urlencode($address) .
+      "&Camp_Institution_Data.Email=" . urlencode($pocEmail) .
+      "&Camp_Institution_Data.Contact_Number=" . urlencode($pocContactNumber),
       $contactId
     ),
   ],
wp-content/civi-extensions/goonjcustom/Civi/InstitutionMaterialContributionService.php (1)

218-218: ⚠️ Potential issue

Use secure file loading mechanism.

Using file_get_contents directly on user-accessible paths could be dangerous if the paths are manipulated.

Consider using WordPress's built-in file handling functions:

-    $imageData = array_map(fn ($path) => base64_encode(file_get_contents($path)), $paths);
+    $imageData = array_map(function($path) {
+        if (!file_exists($path) || !is_readable($path)) {
+            return '';
+        }
+        return base64_encode(file_get_contents($path));
+    }, $paths);
🧹 Nitpick comments (5)
wp-content/civi-extensions/goonjcustom/cli/assign-contact-data.php (2)

17-17: Fix typo in group name constant.

The constant SOURCE_GROUP_NAME contains a typo in the word "institution".

-define('SOURCE_GROUP_NAME', 'instituion-group');
+define('SOURCE_GROUP_NAME', 'institution-group');

71-81: Simplify data presence check.

The current implementation checks each field individually. Consider using array_filter for a more concise check.

-    $hasData = !empty($organization['Institute_Registration.City']) 
-      || !empty($organization['Institute_Registration.Address'])
-      || !empty($organization['Institute_Registration.Postal_Code'])
-      || !empty($organization['Institute_Registration.Contact_number_of_Institution'])
-      || !empty($organization['Institute_Registration.Email_of_Institute']);
+    $hasData = !empty(array_filter($organization, fn($value) => !empty($value)));
wp-content/civi-extensions/goonjcustom/Civi/InstitutionMaterialContributionService.php (1)

224-335: Move HTML template to a separate file.

The HTML generation is embedded in the service class, violating the Single Responsibility Principle.

Consider moving the HTML template to a separate file (e.g., templates/contribution-receipt.php) and use WordPress's template loading functions to include it.

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

573-578: Address field update looks good, but consider extracting common functionality.

The address field update is correct, but there's significant code duplication between this service and InstitutionCollectionCampService. Consider:

  1. Creating a shared trait for common organization operations
  2. Moving email templates to separate files

602-614: Move HTML email templates to separate files.

The HTML email templates are currently hardcoded in the service class. This violates separation of concerns and makes the templates harder to maintain.

Consider moving these templates to separate .html.tpl files in a templates directory:

-    $html = "
-    <p>Dear MMT team,</p>
-    <p>This is to inform you that a vehicle has been sent from camp <strong>$campCode</strong> at <strong>$campAddress</strong>.</p>
-    ...";
+    $templatePath = __DIR__ . '/../templates/emails/mmt-notification.html.tpl';
+    $html = file_get_contents($templatePath);
+    $html = str_replace(
+        ['{{campCode}}', '{{campAddress}}'],
+        [$campCode, $campAddress],
+        $html
+    );

Also applies to: 732-736, 854-866

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70f5ebf and c2754fc.

📒 Files selected for processing (6)
  • wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionCollectionCampLinks.php (2 hunks)
  • wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionDroppingCenterLinks.php (2 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionCollectionCampService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionDroppingCenterService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/Civi/InstitutionMaterialContributionService.php (1 hunks)
  • wp-content/civi-extensions/goonjcustom/cli/assign-contact-data.php (1 hunks)
🔇 Additional comments (2)
wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionCollectionCampLinks.php (1)

109-149: ⚠️ Potential issue

Sanitize URL parameters to prevent XSS.

Similar to the dropping center links, the URL generation includes unsanitized user data.

Apply the same fix using urlencode() for all user-provided parameters in the URL generation.

wp-content/civi-extensions/goonjcustom/Civi/InstitutionCollectionCampService.php (1)

789-813: Move HTML email templates to separate files.

Similar to InstitutionDroppingCenterService, the email templates should be moved out of the service class.

Also applies to: 825-836, 841-866

Comment on lines +54 to +61
$organization = Organization::get(FALSE)
->addSelect(
'Institute_Registration.City',
'Institute_Registration.Address',
'Institute_Registration.Postal_Code',
'Institute_Registration.Contact_number_of_Institution',
'Institute_Registration.Email_of_Institute'
)
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

Update field names to use new schema.

The organization query still uses old field names from Institute_Registration. For consistency with other files in this PR, these should be updated to use the new schema.

 $organization = Organization::get(FALSE)
   ->addSelect(
-    'Institute_Registration.City',
-    'Institute_Registration.Address',
-    'Institute_Registration.Postal_Code',
-    'Institute_Registration.Contact_number_of_Institution',
-    'Institute_Registration.Email_of_Institute'
+    'address_primary.city',
+    'address_primary.street_address',
+    'address_primary.postal_code',
+    'phone_primary.phone',
+    'email_primary.email'
   )
📝 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
$organization = Organization::get(FALSE)
->addSelect(
'Institute_Registration.City',
'Institute_Registration.Address',
'Institute_Registration.Postal_Code',
'Institute_Registration.Contact_number_of_Institution',
'Institute_Registration.Email_of_Institute'
)
$organization = Organization::get(FALSE)
->addSelect(
'address_primary.city',
'address_primary.street_address',
'address_primary.postal_code',
'phone_primary.phone',
'email_primary.email'
)

Comment on lines 56 to 59
$this->_organization = Organization::get(FALSE)
->addSelect('display_name', 'Institute_Registration.Email_of_Institute', 'Institute_Registration.Contact_number_of_Institution', 'Institute_Registration.Address')
->addSelect('display_name', 'Institute_Registration.Email_of_Institute', 'Institute_Registration.Contact_number_of_Institution', 'address_primary.street_address')
->addWhere('id', '=', $organizationId)
->execute()->single();
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

Standardize field selection to use new schema.

The organization query mixes old and new schema field names. For consistency, use the new schema throughout.

 $this->_organization = Organization::get(FALSE)
-  ->addSelect('display_name', 'Institute_Registration.Email_of_Institute', 'Institute_Registration.Contact_number_of_Institution', 'address_primary.street_address')
+  ->addSelect('display_name', 'email_primary.email', 'phone_primary.phone', 'address_primary.street_address')
   ->addWhere('id', '=', $organizationId)
   ->execute()->single();
📝 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
$this->_organization = Organization::get(FALSE)
->addSelect('display_name', 'Institute_Registration.Email_of_Institute', 'Institute_Registration.Contact_number_of_Institution', 'Institute_Registration.Address')
->addSelect('display_name', 'Institute_Registration.Email_of_Institute', 'Institute_Registration.Contact_number_of_Institution', 'address_primary.street_address')
->addWhere('id', '=', $organizationId)
->execute()->single();
$this->_organization = Organization::get(FALSE)
->addSelect('display_name', 'email_primary.email', 'phone_primary.phone', 'address_primary.street_address')
->addWhere('id', '=', $organizationId)
->execute()->single();

Comment on lines +656 to +661
->addSelect('address_primary.street_address', 'display_name')
->addWhere('id', '=', $organizationId)
->execute()->single();

$nameOfInstitution = $organization['display_name'];
$addressOfInstitution = $organization['Institute_Registration.Address'];
$addressOfInstitution = $organization['address_primary.street_address'];
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

Address field update looks good, but consider consolidating duplicate code.

The address field update is correct, but this service shares a lot of duplicate code with InstitutionDroppingCenterService, including:

  • Organization address retrieval
  • Email template generation
  • Coordinator assignment logic

Consider creating an abstract base service or traits to share common functionality:

trait OrganizationAddressable {
    protected function getOrganizationAddress($organizationId) {
        return Organization::get(TRUE)
            ->addSelect('address_primary.street_address', 'display_name')
            ->addWhere('id', '=', $organizationId)
            ->execute()->single();
    }
}

Copy link
Copy Markdown

@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: 0

🧹 Nitpick comments (3)
wp-content/civi-extensions/goonjcustom/cli/assign-group-to-individual.php (3)

17-17: Consider a more descriptive constant name.

The constant name SOURCE_GROUP_NAME could be more specific to better reflect its purpose in assigning POCs for institutions. Consider renaming it to INSTITUTION_GROUP_NAME or SOURCE_INSTITUTION_GROUP.

-define('SOURCE_GROUP_NAME', 'Institution');
+define('INSTITUTION_GROUP_NAME', 'Institution');

12-14: Consider implementing structured logging.

While the error handling is thorough, the logging could be improved by implementing a structured logging system. This would make it easier to parse and analyze logs, especially when running at scale.

Consider using a logging library or implementing a simple logging class:

class Logger {
    public static function info(string $message, array $context = []): void {
        echo json_encode([
            'level' => 'INFO',
            'timestamp' => date('c'),
            'message' => $message,
            'context' => $context
        ]) . "\n";
    }
    
    public static function error(string $message, array $context = []): void {
        echo json_encode([
            'level' => 'ERROR',
            'timestamp' => date('c'),
            'message' => $message,
            'context' => $context
        ]) . "\n";
    }
}

// Usage example:
Logger::info("Skipping contact", ['contact_id' => $contactId, 'reason' => 'No state assigned']);

Also applies to: 73-76, 88-91, 95-98, 107-110


16-17: Consider externalizing configuration.

Hard-coded configuration values like group names could be moved to a configuration file. This would make the script more maintainable and easier to update across environments.

Consider creating a config file:

// config/groups.php
return [
    'institution' => [
        'source_group' => 'Institution',
        'use_case' => 'chapter-contacts',
    ]
];

// Usage in script
$config = require_once __DIR__ . '/config/groups.php';
define('SOURCE_GROUP_NAME', $config['institution']['source_group']);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2754fc and 917f7b9.

📒 Files selected for processing (2)
  • wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionCollectionCampLinks.php (2 hunks)
  • wp-content/civi-extensions/goonjcustom/cli/assign-group-to-individual.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wp-content/civi-extensions/goonjcustom/CRM/Goonjcustom/Form/InstitutionCollectionCampLinks.php
🔇 Additional comments (1)
wp-content/civi-extensions/goonjcustom/cli/assign-group-to-individual.php (1)

24-32: Well-structured implementation with clear separation of concerns!

The code demonstrates good practices:

  • Functions follow single responsibility principle
  • Clear error handling with fallback logic
  • Proper type hints and return types
  • Descriptive variable names and logging

Also applies to: 43-65, 70-120

@belwalshubham belwalshubham merged commit 424fd43 into develop Feb 19, 2025
@belwalshubham belwalshubham deleted the feat/organization-code-cleanups branch February 19, 2025 08:33
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