Skip to content

Migration Script to Add Glific NGO to AI Platform: Onboarding, Credential and Assistant Sync#291

Merged
avirajsingh7 merged 9 commits intoglific_migrationfrom
glific_mirgation_script
Jul 29, 2025
Merged

Migration Script to Add Glific NGO to AI Platform: Onboarding, Credential and Assistant Sync#291
avirajsingh7 merged 9 commits intoglific_migrationfrom
glific_mirgation_script

Conversation

@avirajsingh7
Copy link
Copy Markdown
Collaborator

@avirajsingh7 avirajsingh7 commented Jul 23, 2025

This PR introduces a complete, migration utility to onboard Glific NGOs and their bots into the AI Platform. The migration consists of three distinct processors, each responsible for a specific phase:

Target issue #289 and #290

Organization and Project Onboarding

  • Reads from sample_input.csv with columns like organization_name, project_name, email, password, and user_name
  • For each row:
    Calls the /onboard endpoint to create the organization, project, and user
    Generates and stores API key per project

Credential Synchronization

  • Reads organization_id and project_id from a CSV
  • Sends a POST request to the /credentials/ endpoint to attach an OpenAI API key
  • Uses SuperUserApiKey for authentication
  • Outputs results to credentials_output.csv

Assistant Ingestion

  • Reads a CSV with assistant_id and api_key
  • For each row:
    Calls /assistant/{assistant_id}/ingest with the corresponding API key
    Ingests the assistant into the internal database
  • Outputs results to assistants_output.csv

Structure & Utilities

  • Shared BaseCSVProcessor class for reusable CSV handling and validation
  • APIClient class for robust request logic with retry, logging, and error capture
  • Validator module for email, password, assistant ID, and API key formats
  • Logging is streamed both to console and file for traceability

Summary by CodeRabbit

  • New Features

    • Introduced tools for processing and validating CSV files for onboarding organizations, syncing assistants, and migrating credentials.
    • Added automated validation for emails, passwords, API keys, and assistant IDs.
    • Enabled batch processing with detailed logging and output reports for each operation.
    • Provided command-line scripts to run onboarding, assistant sync, and credential migration workflows.
  • Chores

    • Updated configuration to ignore log files in version control.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 23, 2025

Walkthrough

A set of new modules and scripts were introduced to support CSV-based migration and onboarding processes, including base and specialized CSV processors, API client utilities, and validators. Entry-point scripts for running onboarding, assistant sync, and credential sync workflows were added. Logging, validation, and error handling are consistently integrated throughout the new code.

Changes

File(s) Change Summary
backend/.gitignore Added *.logs and *.log patterns to ignore log files.
backend/glific_migration/base_processor.py Introduced BaseCSVProcessor abstract class for structured CSV processing, including logging and workflow methods.
backend/glific_migration/client.py Added APIClient class for HTTP POST requests with retry and error handling.
backend/glific_migration/validator.py Added utility functions for validating required fields, email, password, API key, and assistant ID formats.
backend/glific_migration/organization_onboarding/processor.py Added OnboardProcessor class for onboarding organizations via CSV and API integration.
backend/glific_migration/organization_onboarding/run_onboarding.py Added script with main() to run organization onboarding workflow.
backend/glific_migration/sync_assistant/processor.py Added AssistantIngestProcessor for ingesting assistants via CSV and API.
backend/glific_migration/sync_assistant/sync_assistant.py Added script with main() to run assistant ingestion workflow.
backend/glific_migration/sync_credentials/processor.py Added CredentialProcessor for syncing credentials via CSV and API.
backend/glific_migration/sync_credentials/run_credentials.py Added script with main() to run credential synchronization workflow.
backend/glific_migration/config.json Added configuration file specifying API URLs, API keys, and CSV file paths for onboarding, assistant, and credential sync.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Script
    participant Processor
    participant APIClient
    participant API

    User->>Script: Run entry-point script (e.g., run_onboarding.py)
    Script->>Processor: Instantiate with input/output files, API params
    Script->>Processor: Call run()
    Processor->>Processor: load_csv()
    Processor->>Processor: validate_csv(rows)
    alt Validation passes
        Processor->>Processor: process_rows(rows)
        loop For each row
            Processor->>APIClient: post(url, data)
            APIClient->>API: POST request
            API-->>APIClient: Response
            APIClient-->>Processor: (success, response)
            Processor->>Processor: append_to_csv(result)
        end
    else Validation fails
        Processor->>Processor: Log errors, abort
    end
    Processor-->>Script: Done
Loading

Estimated code review effort

4 (~90 minutes)

Possibly related issues

Poem

In the warren of code, new tunnels are spun,
CSVs are processed, migrations begun.
With logs now ignored and validators in tow,
Each row gets a check before onward it goes.
API clients hop, credentials in hand—
The rabbits of code sync data as planned!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this 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.

@avirajsingh7 avirajsingh7 self-assigned this Jul 23, 2025
@avirajsingh7 avirajsingh7 added the enhancement New feature or request label Jul 23, 2025
@codecov
Copy link
Copy Markdown

codecov Bot commented Jul 23, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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: 5

🧹 Nitpick comments (11)
backend/glific_migration/base_processor.py (2)

5-5: Use built-in types instead of deprecated typing module imports

The code uses deprecated typing imports. Python 3.9+ supports using built-in types directly.

Replace the import and update type annotations:

-from typing import List, Dict
+from typing import List, Dict  # Can be removed after updating annotations

 class BaseCSVProcessor(ABC):
     """Base class for CSV processing with common functionality."""

-    def __init__(self, input_file: str, output_file: str, headers: List[str]):
+    def __init__(self, input_file: str, output_file: str, headers: list[str]):

-    def load_csv(self) -> List[Dict[str, str]]:
+    def load_csv(self) -> list[dict[str, str]]:

-    def append_to_csv(self, row: Dict[str, str]) -> None:
+    def append_to_csv(self, row: dict[str, str]) -> None:

     @abstractmethod
-    def validate_csv(self, rows: List[Dict[str, str]]) -> bool:
+    def validate_csv(self, rows: list[dict[str, str]]) -> bool:

     @abstractmethod
-    def process_rows(self, rows: List[Dict[str, str]]) -> None:
+    def process_rows(self, rows: list[dict[str, str]]) -> None:

Also applies to: 13-13, 46-46, 58-58, 69-69, 74-74


46-56: Consider memory efficiency for large CSV files

Loading the entire CSV into memory might cause issues with large files. Consider implementing a streaming approach for better scalability.

For large files, consider yielding rows instead of loading all at once:

def load_csv_streaming(self) -> Generator[dict[str, str], None, None]:
    """Stream CSV file row by row."""
    try:
        with open(self.input_file, newline="", encoding="utf-8") as f:
            reader = csv.DictReader(f)
            for row in reader:
                yield row
    except FileNotFoundError:
        self.logger.error(f"Input file not found: {self.input_file}")
        raise
    except Exception as e:
        self.logger.error(f"Error reading CSV file {self.input_file}: {str(e)}")
        raise
backend/glific_migration/client.py (2)

5-5: Update deprecated type annotations

Replace deprecated typing imports with built-in types for Python 3.9+ compatibility.

-from typing import Tuple, Dict, Optional
+from typing import Optional

27-27: Update method signature to use modern type annotations

Update the type hints to use built-in types instead of deprecated typing module types.

-    def post(self, url: str, data: Optional[Dict] = None) -> Tuple[bool, Dict]:
+    def post(self, url: str, data: Optional[dict] = None) -> tuple[bool, dict]:
backend/glific_migration/sync_credentials/processor.py (1)

2-2: Remove unused import and update deprecated type annotations

The Set type is imported but never used. Also update deprecated type annotations.

-from typing import List, Dict, Set
+from typing import List, Dict

Then update the type annotations in method signatures:

-    def validate_csv(self, rows: List[Dict[str, str]]) -> bool:
+    def validate_csv(self, rows: list[dict[str, str]]) -> bool:
-    def process_rows(self, rows: List[Dict[str, str]]) -> None:
+    def process_rows(self, rows: list[dict[str, str]]) -> None:
backend/glific_migration/organization_onboarding/processor.py (1)

2-2: Remove unused import and update deprecated type annotations

The Set type is imported but never used. Also update deprecated type annotations.

-from typing import List, Dict, Set
+from typing import List, Dict

Then update the type annotations in method signatures to use built-in types.

backend/glific_migration/validator.py (2)

2-2: Update deprecated type annotations

Replace deprecated typing imports with built-in types for better compatibility.

-from typing import List, Dict, Tuple, Set
+from typing import List, Dict, Tuple, Set

Then update the function signatures:

-def validate_required_fields(row: Dict[str, str], fields: Set[str]) -> List[str]:
+def validate_required_fields(row: dict[str, str], fields: set[str]) -> list[str]:
-def validate_email_format(email: str) -> Tuple[bool, str]:
+def validate_email_format(email: str) -> tuple[bool, str]:

Also applies to: 6-6, 11-11


20-22: Consider additional password validation rules

The current validation only checks minimum length. Consider if additional rules are needed such as complexity requirements.

If the API requires specific password complexity rules, I can help implement additional validation checks.

backend/glific_migration/sync_assistant/processor.py (3)

2-2: Remove unused import and update deprecated type annotations

The Set type is imported but never used. Also update deprecated type annotations.

-from typing import List, Dict, Set
+from typing import List, Dict

36-40: Remove redundant empty value checks

The validate_required_fields function already checks for empty values after stripping whitespace, making these explicit checks redundant.

-            if not row.get("assistant_id", "").strip():
-                row_errors.append("Empty assistant_id")
-
-            if not row.get("api_key", "").strip():
-                row_errors.append("Empty api_key")

71-71: Consider URL-encoding the assistant_id parameter

While the assistant_id is validated to contain only alphanumeric characters, it's a best practice to URL-encode path parameters.

+from urllib.parse import quote
+
             url = f"{self.base_url}/assistant/{assistant_id}/ingest"
+            # Or use: url = f"{self.base_url}/assistant/{quote(assistant_id, safe='')}/ingest"
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between eeba2c2 and 18fa5eb.

⛔ Files ignored due to path filters (3)
  • backend/glific_migration/organization_onboarding/sample_input.csv is excluded by !**/*.csv
  • backend/glific_migration/sync_assistant/sample_input.csv is excluded by !**/*.csv
  • backend/glific_migration/sync_credentials/sample_input.csv is excluded by !**/*.csv
📒 Files selected for processing (10)
  • backend/.gitignore (1 hunks)
  • backend/glific_migration/base_processor.py (1 hunks)
  • backend/glific_migration/client.py (1 hunks)
  • backend/glific_migration/organization_onboarding/processor.py (1 hunks)
  • backend/glific_migration/organization_onboarding/run_onboarding.py (1 hunks)
  • backend/glific_migration/sync_assistant/processor.py (1 hunks)
  • backend/glific_migration/sync_assistant/sync_assistant.py (1 hunks)
  • backend/glific_migration/sync_credentials/processor.py (1 hunks)
  • backend/glific_migration/sync_credentials/run_credentials.py (1 hunks)
  • backend/glific_migration/validator.py (1 hunks)
🧬 Code Graph Analysis (1)
backend/glific_migration/sync_credentials/processor.py (3)
backend/glific_migration/base_processor.py (4)
  • BaseCSVProcessor (10-90)
  • validate_csv (69-71)
  • process_rows (74-76)
  • append_to_csv (58-66)
backend/glific_migration/client.py (2)
  • APIClient (10-50)
  • post (27-50)
backend/glific_migration/validator.py (2)
  • validate_required_fields (6-8)
  • is_valid_api_key (25-31)
🪛 Ruff (0.12.2)
backend/glific_migration/client.py

5-5: typing.Tuple is deprecated, use tuple instead

(UP035)


5-5: typing.Dict is deprecated, use dict instead

(UP035)


27-27: Use X | None for type annotations

Convert to X | None

(UP045)


27-27: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


27-27: Use tuple instead of Tuple for type annotation

Replace with tuple

(UP006)


27-27: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/organization_onboarding/processor.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


2-2: typing.Set imported but unused

Remove unused import: typing.Set

(F401)


41-41: Use list instead of List for type annotation

Replace with list

(UP006)


41-41: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


78-78: Use list instead of List for type annotation

Replace with list

(UP006)


78-78: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/validator.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Tuple is deprecated, use tuple instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


6-6: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


6-6: Use set instead of Set for type annotation

Replace with set

(UP006)


6-6: Use list instead of List for type annotation

Replace with list

(UP006)


11-11: Use tuple instead of Tuple for type annotation

Replace with tuple

(UP006)

backend/glific_migration/sync_credentials/processor.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


2-2: typing.Set imported but unused

Remove unused import: typing.Set

(F401)


29-29: Use list instead of List for type annotation

Replace with list

(UP006)


29-29: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


63-63: Use list instead of List for type annotation

Replace with list

(UP006)


63-63: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/sync_assistant/processor.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


2-2: typing.Set imported but unused

Remove unused import: typing.Set

(F401)


25-25: Use list instead of List for type annotation

Replace with list

(UP006)


25-25: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


62-62: Use list instead of List for type annotation

Replace with list

(UP006)


62-62: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/base_processor.py

5-5: typing.List is deprecated, use list instead

(UP035)


5-5: typing.Dict is deprecated, use dict instead

(UP035)


13-13: Use list instead of List for type annotation

Replace with list

(UP006)


46-46: Use list instead of List for type annotation

Replace with list

(UP006)


46-46: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


58-58: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


69-69: Use list instead of List for type annotation

Replace with list

(UP006)


69-69: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


74-74: Use list instead of List for type annotation

Replace with list

(UP006)


74-74: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/glific_migration/sync_credentials/processor.py (3)
backend/glific_migration/base_processor.py (4)
  • BaseCSVProcessor (10-90)
  • validate_csv (69-71)
  • process_rows (74-76)
  • append_to_csv (58-66)
backend/glific_migration/client.py (2)
  • APIClient (10-50)
  • post (27-50)
backend/glific_migration/validator.py (2)
  • validate_required_fields (6-8)
  • is_valid_api_key (25-31)
🪛 Ruff (0.12.2)
backend/glific_migration/client.py

5-5: typing.Tuple is deprecated, use tuple instead

(UP035)


5-5: typing.Dict is deprecated, use dict instead

(UP035)


27-27: Use X | None for type annotations

Convert to X | None

(UP045)


27-27: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


27-27: Use tuple instead of Tuple for type annotation

Replace with tuple

(UP006)


27-27: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/organization_onboarding/processor.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


2-2: typing.Set imported but unused

Remove unused import: typing.Set

(F401)


41-41: Use list instead of List for type annotation

Replace with list

(UP006)


41-41: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


78-78: Use list instead of List for type annotation

Replace with list

(UP006)


78-78: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/validator.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Tuple is deprecated, use tuple instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


6-6: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


6-6: Use set instead of Set for type annotation

Replace with set

(UP006)


6-6: Use list instead of List for type annotation

Replace with list

(UP006)


11-11: Use tuple instead of Tuple for type annotation

Replace with tuple

(UP006)

backend/glific_migration/sync_credentials/processor.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


2-2: typing.Set imported but unused

Remove unused import: typing.Set

(F401)


29-29: Use list instead of List for type annotation

Replace with list

(UP006)


29-29: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


63-63: Use list instead of List for type annotation

Replace with list

(UP006)


63-63: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/sync_assistant/processor.py

2-2: typing.List is deprecated, use list instead

(UP035)


2-2: typing.Dict is deprecated, use dict instead

(UP035)


2-2: typing.Set is deprecated, use set instead

(UP035)


2-2: typing.Set imported but unused

Remove unused import: typing.Set

(F401)


25-25: Use list instead of List for type annotation

Replace with list

(UP006)


25-25: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


62-62: Use list instead of List for type annotation

Replace with list

(UP006)


62-62: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

backend/glific_migration/base_processor.py

5-5: typing.List is deprecated, use list instead

(UP035)


5-5: typing.Dict is deprecated, use dict instead

(UP035)


13-13: Use list instead of List for type annotation

Replace with list

(UP006)


46-46: Use list instead of List for type annotation

Replace with list

(UP006)


46-46: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


58-58: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


69-69: Use list instead of List for type annotation

Replace with list

(UP006)


69-69: Use dict instead of Dict for type annotation

Replace with dict

(UP006)


74-74: Use list instead of List for type annotation

Replace with list

(UP006)


74-74: Use dict instead of Dict for type annotation

Replace with dict

(UP006)

🔇 Additional comments (3)
backend/.gitignore (1)

9-10: LGTM!

The additions properly exclude log files from version control, which aligns with the logging functionality introduced in the migration modules.

backend/glific_migration/client.py (1)

35-47: Fix potential UnboundLocalError in error handling

The response variable may not be defined when the HTTPError exception is caught, leading to an UnboundLocalError when trying to access response.json().

         except requests.exceptions.HTTPError as http_err:
+            error_detail = "No error detail provided."
             try:
-                error_detail = response.json().get("error", "No error detail provided.")
+                if 'response' in locals():
+                    error_detail = response.json().get("error", "No error detail provided.")
             except Exception:
                 error_detail = "Unable to parse error response."

Likely an incorrect or invalid review comment.

backend/glific_migration/organization_onboarding/processor.py (1)

84-84: Consider filtering sensitive data before sending to API

The entire row data, including the password field, is being sent to the API endpoint. Ensure that the API endpoint expects and properly handles sensitive fields like passwords.

Consider filtering the data to only include expected fields:

payload = {
    "organization_name": row.get("organization_name"),
    "project_name": row.get("project_name"),
    "email": row.get("email"),
    "password": row.get("password"),
    "user_name": row.get("user_name")
}
success, resp = self.client.post(self.api_url, data=payload)

Comment thread backend/glific_migration/base_processor.py
Comment thread backend/glific_migration/organization_onboarding/run_onboarding.py
Comment thread backend/glific_migration/sync_assistant/sync_assistant.py
Comment thread backend/glific_migration/sync_credentials/processor.py
Comment thread backend/glific_migration/sync_credentials/run_credentials.py
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

🧹 Nitpick comments (3)
backend/glific_migration/organization_onboarding/run_onboarding.py (1)

9-10: Remove unnecessary mode argument and add error handling.

The static analysis tool correctly identifies that the "r" mode argument is unnecessary since it's the default for open(). Additionally, the file operations lack proper error handling.

Apply this diff:

-    with open(base_dir / "../config.json", "r") as file:
-        config = json.load(file)
+    try:
+        with open(base_dir / "../config.json") as file:
+            config = json.load(file)
+    except FileNotFoundError:
+        raise FileNotFoundError("Configuration file 'config.json' not found in parent directory")
+    except json.JSONDecodeError as e:
+        raise ValueError(f"Invalid JSON in configuration file: {e}")
backend/glific_migration/sync_assistant/sync_assistant.py (1)

9-10: Apply static analysis suggestion to remove unnecessary mode argument

The "r" mode argument is unnecessary when opening files for reading as it's the default behavior.

-    with open(base_dir / "../config.json", "r") as file:
+    with open(base_dir / "../config.json") as file:
backend/glific_migration/sync_credentials/run_credentials.py (1)

9-9: Remove unnecessary file mode argument.

The "r" mode is the default when opening files, making this argument redundant.

-    with open(base_dir / "../config.json", "r") as file:
+    with open(base_dir / "../config.json") as file:
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 18fa5eb and 48a06ad.

📒 Files selected for processing (4)
  • backend/glific_migration/config.json (1 hunks)
  • backend/glific_migration/organization_onboarding/run_onboarding.py (1 hunks)
  • backend/glific_migration/sync_assistant/sync_assistant.py (1 hunks)
  • backend/glific_migration/sync_credentials/run_credentials.py (1 hunks)
🪛 Ruff (0.12.2)
backend/glific_migration/organization_onboarding/run_onboarding.py

9-9: Unnecessary mode argument

Remove mode argument

(UP015)

backend/glific_migration/sync_assistant/sync_assistant.py

9-9: Unnecessary mode argument

Remove mode argument

(UP015)

backend/glific_migration/sync_credentials/run_credentials.py

9-9: Unnecessary mode argument

Remove mode argument

(UP015)

✅ Files skipped from review due to trivial changes (1)
  • backend/glific_migration/config.json
🧰 Additional context used
🪛 Ruff (0.12.2)
backend/glific_migration/organization_onboarding/run_onboarding.py

9-9: Unnecessary mode argument

Remove mode argument

(UP015)

backend/glific_migration/sync_assistant/sync_assistant.py

9-9: Unnecessary mode argument

Remove mode argument

(UP015)

backend/glific_migration/sync_credentials/run_credentials.py

9-9: Unnecessary mode argument

Remove mode argument

(UP015)

🔇 Additional comments (6)
backend/glific_migration/organization_onboarding/run_onboarding.py (1)

8-23: Good improvement from hardcoded values to centralized configuration.

This implementation addresses the security concerns raised in previous reviews by moving from hardcoded API keys and URLs to a centralized configuration file approach. This enhances both security and maintainability.

backend/glific_migration/sync_assistant/sync_assistant.py (3)

1-3: LGTM: Clean imports structure

The imports are well-organized with standard library imports first, followed by the project-specific import.


8-21: Past review comment has been addressed

Good improvement! The hardcoded API URL issue from the previous review has been resolved by reading the configuration from config.json. This makes the script much more flexible for different environments.


24-25: LGTM: Standard entry point guard

The entry point guard follows Python best practices for making the script executable.

backend/glific_migration/sync_credentials/run_credentials.py (2)

1-6: LGTM!

The imports and path setup are well-structured, using appropriate standard library modules and following good practices for relative path resolution.


28-29: LGTM!

Standard and correct implementation of the script entry point.

Comment thread backend/glific_migration/organization_onboarding/run_onboarding.py
Comment thread backend/glific_migration/sync_assistant/sync_assistant.py
Comment thread backend/glific_migration/sync_credentials/run_credentials.py
@avirajsingh7 avirajsingh7 changed the base branch from main to glific_migration July 24, 2025 04:46
@AkhileshNegi AkhileshNegi requested a review from kartpop July 25, 2025 04:58
Copy link
Copy Markdown
Collaborator

@kartpop kartpop left a comment

Choose a reason for hiding this comment

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

Should the directory structure be backend/scripts/glific_migration instead of backend/glific_migration?

That way we can keep all stand-alone progarms/scripts as part of the scripts/ dir

with open(base_dir / "../config.json", "r") as file:
config = json.load(file)

input_file = base_dir / config["organization_onboarding"]["input_csv"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Would be good to avoid magic strings like "organization_onboarding", "input_csv".

Libraries like dynaconf can help; they support key traversing like settings.organization_onboarding.input_csv


input_file = base_dir / config["organization_onboarding"]["input_csv"]
output_file = base_dir / config["organization_onboarding"]["output_csv"]
api_url = config["base_url"] + "/onboard"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

API endpoints like "/onboard" may also be kept in a string constant somewhere in a common file.

The routes in backend/app/api/routes/onboarding.py can also use the same string constant.

@router.post(
    "/onboard",
    dependencies=[Depends(get_current_active_superuser)],
    response_model=OnboardingResponse,
)

Not an urgent change, can be picked up as part of a separate PR where all such routes, other constant strings are refactored.

with open(base_dir / "../config.json", "r") as file:
config = json.load(file)

input_csv = base_dir / config["assistant_ingest"]["input_csv"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

same as for organization_onboarding, can benefit from use of a config management library

@avirajsingh7 avirajsingh7 merged commit 98f5bb1 into glific_migration Jul 29, 2025
3 checks passed
@avirajsingh7 avirajsingh7 deleted the glific_mirgation_script branch July 29, 2025 04:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request ready-for-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sync Assistants Used by Glific Bots into AI Platform Migrate Glific Organizations and Bots to AI Platform

2 participants