Skip to content

Feat: Add created_by, updated_by to conf tables#421

Merged
Ashutosh619-sudo merged 1 commit intomasterfrom
add-created-updated-by
Jan 13, 2025
Merged

Feat: Add created_by, updated_by to conf tables#421
Ashutosh619-sudo merged 1 commit intomasterfrom
add-created-updated-by

Conversation

@Ashutosh619-sudo
Copy link
Contributor

@coderabbitai
Copy link

coderabbitai bot commented Jan 8, 2025

Walkthrough

The pull request introduces a comprehensive enhancement to track user information during record creation and updates across multiple models in the Django application. A new mixin AutoAddCreateUpdateInfoMixin is implemented to automatically capture the user responsible for creating and modifying records. This is achieved by adding created_by and updated_by fields to several models, including ExpenseGroupSettings, WorkspaceGeneralSettings, and GeneralMapping. The changes also update various serializers, views, and methods to pass and handle user context during database operations.

Changes

File Path Change Summary
apps/fyle/models.py Added AutoAddCreateUpdateInfoMixin to ExpenseGroupSettings
apps/mappings/models.py Added AutoAddCreateUpdateInfoMixin to GeneralMapping
apps/workspaces/models.py Added AutoAddCreateUpdateInfoMixin to WorkspaceGeneralSettings
requirements.txt Updated fyle-accounting-mappings from 1.35.0 to 1.36.3
Multiple serializers Updated to handle user context in update methods
Multiple views Added get_serializer_context to pass request to serializers

Sequence Diagram

sequenceDiagram
    participant User
    participant View
    participant Serializer
    participant Model
    
    User->>View: Make update request
    View->>Serializer: Pass request context
    Serializer->>Model: Update with user info
    Model-->>Serializer: Record updated
    Serializer-->>View: Return updated instance
    View-->>User: Respond with updated data
Loading

Poem

🐰 Tracking changes with a hop and a bound,
User context now perfectly found!
From created to updated with glee,
Rabbit's magic of metadata, whoopee!
Migrations dance, models sing their song 🎉


🪧 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.

@github-actions
Copy link

github-actions bot commented Jan 8, 2025

Tests Skipped Failures Errors Time
166 0 💤 0 ❌ 0 🔥 1m 10s ⏱️

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

🔭 Outside diff range comments (1)
apps/workspaces/apis/import_settings/serializers.py (1)

Line range hint 122-122: Pass user to trigger methods to maintain user context

Since the methods pre_save_workspace_general_settings, post_save_workspace_general_settings, pre_save_mapping_settings, and post_save_mapping_settings have been updated to accept the user parameter, consider passing user=user when calling these methods to ensure that user context is maintained throughout the trigger process.

Apply this diff to include user in the method calls:

-            trigger.pre_save_workspace_general_settings(workspace_general_settings)
+            trigger.pre_save_workspace_general_settings(workspace_general_settings, user=user)

-            trigger.post_save_workspace_general_settings(workspace_general_settings_instance)
+            trigger.post_save_workspace_general_settings(workspace_general_settings_instance, user=user)

-            trigger.pre_save_mapping_settings()
+            trigger.pre_save_mapping_settings(user=user)

-            trigger.post_save_mapping_settings(workspace_general_settings_instance)
+            trigger.post_save_mapping_settings(workspace_general_settings_instance, user=user)

Also applies to: 155-155, 160-160, 216-216

🧹 Nitpick comments (14)
tests/test_fyle/fixtures.py (1)

560-561: Use standard test email domains.

While the addition of created_by and updated_by fields aligns with the PR objectives, consider using example.com domain for test emails to follow best practices.

-        "created_by": "ashut@asjkdnsa.com",
-        "updated_by": "asdksaj@gnioa.com"
+        "created_by": "user1@example.com",
+        "updated_by": "user2@example.com"
apps/workspaces/apis/import_settings/views.py (1)

13-20: LGTM! Consider enhancing the docstring.

The implementation correctly adds the request to the serializer context, following Django REST framework patterns.

Consider expanding the docstring to include:

    def get_serializer_context(self):
        """
        Override to include the request in the serializer context.
        This allows serializers to access the current user.
+       Returns:
+           dict: The serializer context including the request object
        """
apps/workspaces/apis/export_settings/views.py (1)

13-20: Consider using a mixin for shared context logic.

While the implementation is correct, this exact code appears in multiple view files. Consider creating a mixin to reduce duplication.

class UserContextMixin:
    def get_serializer_context(self):
        """
        Include the request in the serializer context.
        This allows serializers to access the current user.
        
        Returns:
            dict: The serializer context including the request object
        """
        context = super().get_serializer_context()
        context['request'] = self.request
        return context

class ExportSettingsView(UserContextMixin, generics.RetrieveUpdateAPIView):
    ...
apps/mappings/migrations/0007_auto_20250108_0817.py (1)

14-17: Consider using EmailField for email validation.

Since these fields store email addresses, using EmailField instead of CharField would provide built-in email validation.

-field=models.CharField(blank=True, help_text='Email of the user who created this record', max_length=255, null=True),
+field=models.EmailField(blank=True, help_text='Email of the user who created this record', max_length=255, null=True),
apps/fyle/migrations/0023_auto_20250108_0817.py (1)

13-22: Consider adding database indexes for user tracking fields.

The migration correctly adds the user tracking fields. However, since these fields might be used in filtering or searching operations, consider adding database indexes to improve query performance.

 migrations.AddField(
     model_name='expensegroupsettings',
     name='created_by',
-    field=models.CharField(blank=True, help_text='Email of the user who created this record', max_length=255, null=True),
+    field=models.CharField(blank=True, help_text='Email of the user who created this record', max_length=255, null=True, db_index=True),
 ),
 migrations.AddField(
     model_name='expensegroupsettings',
     name='updated_by',
-    field=models.CharField(blank=True, help_text='Email of the user who last updated this record', max_length=255, null=True),
+    field=models.CharField(blank=True, help_text='Email of the user who last updated this record', max_length=255, null=True, db_index=True),
 ),
apps/workspaces/migrations/0042_auto_20250108_0817.py (1)

13-22: Consider creating a shared migration utility for common field patterns.

The migration is correct but duplicates the pattern from ExpenseGroupSettings. Consider creating a shared migration utility for adding these user tracking fields, as they might be needed in other models.

Example utility in a shared migration file:

def add_user_tracking_fields(apps, schema_editor):
    models_to_update = [
        ('fyle', 'ExpenseGroupSettings'),
        ('workspaces', 'WorkspaceGeneralSettings'),
        # Add more models here
    ]
    
    for app_label, model_name in models_to_update:
        Model = apps.get_model(app_label, model_name)
        schema_editor.add_field(
            Model,
            models.CharField(
                'created_by',
                blank=True,
                null=True,
                max_length=255,
                db_index=True,
                help_text='Email of the user who created this record'
            )
        )
        # Add updated_by field similarly
tests/test_workspaces/fixtures.py (1)

24-25: Use more realistic test data for email addresses.

The current test email addresses (asdvhjasb@anjfas.com, asbdja@nkasnd.com) appear to be randomly generated. Consider using more realistic test email addresses that follow common patterns (e.g., test.user@example.com) for better readability and maintainability.

-        "created_by": "asdvhjasb@anjfas.com",
-        "updated_by": "asbdja@nkasnd.com"
+        "created_by": "test.creator@example.com",
+        "updated_by": "test.updater@example.com"
apps/workspaces/models.py (1)

10-11: Consider consistent application of user tracking across models.

Good use of AutoAddCreateUpdateInfoMixin for adding user tracking. However, other models in the file (like Workspace, XeroCredentials, etc.) might also benefit from this tracking capability.

Also applies to: 146-146

apps/workspaces/apis/export_settings/serializers.py (1)

104-106: Consider extracting user context retrieval to a mixin.

This user context retrieval logic is duplicated across serializers. Consider creating a mixin to handle this common functionality.

class UserContextMixin:
    def get_user_from_context(self):
        request = self.context.get('request')
        return request.user if request and hasattr(request, 'user') else None
tests/test_fyle/test_models.py (1)

51-53: Improve test data setup clarity.

Getting the user from workspace ID 1 while testing workspace ID 98 is confusing and could be fragile. Consider:

  1. Using a fixture to create test user data
  2. Making the test user creation explicit in the test setup
@pytest.fixture
def test_user(db):
    return User.objects.create(email='test@test.com')

def test_expense_group_settings(create_temp_workspace, test_user, db):
    workspace_id = 98
    payload = data["expense_group_settings_payload"]
    
    ExpenseGroupSettings.update_expense_group_settings(payload, workspace_id, test_user)
apps/fyle/models.py (3)

281-281: Update docstring to document user tracking capabilities.

While the mixin inheritance is correctly implemented, the class docstring should be updated to reflect the new user tracking capabilities.

 class ExpenseGroupSettings(AutoAddCreateUpdateInfoMixin, models.Model):
     """
     ExpenseGroupCustomizationSettings
+    
+    Tracks the user who creates and updates expense group settings through created_by
+    and updated_by fields provided by AutoAddCreateUpdateInfoMixin.
     """

342-342: Add type hints and docstring for the method.

The method should include:

  1. Type hint for the user parameter
  2. Docstring documenting the parameters and return value
     @staticmethod
-    def update_expense_group_settings(expense_group_settings: Dict, workspace_id: int, user):
+    def update_expense_group_settings(expense_group_settings: Dict, workspace_id: int, user: Any) -> Tuple[ExpenseGroupSettings, bool]:
+        """
+        Update expense group settings for a workspace.
+
+        Args:
+            expense_group_settings (Dict): Settings to update
+            workspace_id (int): ID of the workspace
+            user (Any): User performing the update
+
+        Returns:
+            Tuple[ExpenseGroupSettings, bool]: Updated settings and creation status
+        """

Line range hint 342-438: Consider refactoring the method for better maintainability.

The method is quite long and handles multiple responsibilities. Consider breaking it down into smaller, focused methods:

  1. Split field processing logic into separate methods
  2. Extract claim number and report ID handling logic
  3. Optimize list operations

Example refactoring:

@staticmethod
def _process_claim_number_logic(settings: List[str]) -> None:
    """Handle claim number and report ID relationship in settings."""
    if "report_id" not in settings:
        if "claim_number" in settings:
            settings.remove("claim_number")
    else:
        settings.append("claim_number")

@staticmethod
def _process_export_date_fields(grouped_by: List[str], export_date_type: str) -> None:
    """Process export date fields in grouped by settings."""
    for field in ALLOWED_FORM_INPUT["export_date_type"]:
        if field in grouped_by:
            grouped_by.remove(field)
    
    if export_date_type != "current_date":
        grouped_by.append(export_date_type)
tests/sql_fixtures/reset_db_fixtures/reset_db.sql (1)

820-821: Consider adding default values and NOT NULL constraints.

The new created_by and updated_by columns are nullable without default values. Since these columns track audit information:

  1. Consider making them NOT NULL to ensure data integrity
  2. Add a default value (e.g., 'system') for existing records
-    created_by character varying(255),
-    updated_by character varying(255)
+    created_by character varying(255) NOT NULL DEFAULT 'system',
+    updated_by character varying(255) NOT NULL DEFAULT 'system'

Also applies to: 1078-1079, 1204-1205, 1546-1547

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 47828f4 and 367ec6d.

📒 Files selected for processing (17)
  • apps/fyle/migrations/0023_auto_20250108_0817.py (1 hunks)
  • apps/fyle/models.py (4 hunks)
  • apps/mappings/migrations/0007_auto_20250108_0817.py (1 hunks)
  • apps/mappings/models.py (2 hunks)
  • apps/workspaces/apis/advanced_settings/serializers.py (3 hunks)
  • apps/workspaces/apis/advanced_settings/views.py (1 hunks)
  • apps/workspaces/apis/export_settings/serializers.py (4 hunks)
  • apps/workspaces/apis/export_settings/views.py (1 hunks)
  • apps/workspaces/apis/import_settings/serializers.py (4 hunks)
  • apps/workspaces/apis/import_settings/views.py (1 hunks)
  • apps/workspaces/migrations/0042_auto_20250108_0817.py (1 hunks)
  • apps/workspaces/models.py (2 hunks)
  • requirements.txt (1 hunks)
  • tests/sql_fixtures/reset_db_fixtures/reset_db.sql (10 hunks)
  • tests/test_fyle/fixtures.py (1 hunks)
  • tests/test_fyle/test_models.py (2 hunks)
  • tests/test_workspaces/fixtures.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • requirements.txt
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: pytest
🔇 Additional comments (11)
apps/workspaces/apis/import_settings/serializers.py (4)

107-108: Properly retrieving user from request context

Good implementation of retrieving the user from the request context, safely handling cases where request or user may not be present.


145-145: Passing user to WorkspaceGeneralSettings.objects.update_or_create

Properly passing user to update_or_create ensures that created_by and updated_by fields are correctly set.


158-158: Passing user to GeneralMapping.objects.update_or_create

Passing user to update_or_create maintains consistency in tracking user actions during updates.


211-211: Passing user to MappingSetting.objects.update_or_create

Ensures that user context is properly associated with mapping settings updates.

apps/workspaces/apis/advanced_settings/views.py (1)

13-20: Code duplication detected.

This is the third instance of identical context handling code.

Please refer to the mixin suggestion in the ExportSettingsView review.

apps/mappings/migrations/0007_auto_20250108_0817.py (1)

12-23: Verify migration safety for production deployment.

Since this migration adds new fields:

  1. Confirm that the fields being nullable won't cause issues with existing queries
  2. Ensure there's a plan to populate these fields for existing records if needed
✅ Verification successful

Migration is safe for production deployment

The migration is safe because:

  • Fields are nullable and optional, consistent with existing model design
  • Model inherits from AutoAddCreateUpdateInfoMixin which will automatically populate these tracking fields for new records
  • No existing queries will be affected as verified in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any non-nullable fields in the model that might affect this migration
rg -l "null=False" apps/mappings/models.py

# Check for existing queries that might be affected
rg "generalmapping" apps/ tests/ | grep -v "migration"

Length of output: 695


Script:

#!/bin/bash
# Check the GeneralMapping model definition
ast-grep --pattern 'class GeneralMapping' -A 20 apps/mappings/models.py

# Look for any views or serializers using this model
rg -l "GeneralMapping" apps/mappings/

Length of output: 235


Script:

#!/bin/bash
# Check model definition and related files
cat apps/mappings/models.py
echo "---SERIALIZER---"
cat apps/mappings/serializers.py
echo "---UTILS---"
cat apps/mappings/utils.py

Length of output: 7325

apps/mappings/models.py (1)

38-38: Verify if TenantMapping should also include user tracking.

While GeneralMapping now includes user tracking via AutoAddCreateUpdateInfoMixin, TenantMapping doesn't have this functionality. Consider if this is intentional or if TenantMapping should also track user information for consistency.

apps/workspaces/apis/advanced_settings/serializers.py (2)

117-117: LGTM: Consistent user tracking implementation.

The user context is properly passed to both WorkspaceGeneralSettings and GeneralMapping update operations.

Also applies to: 128-128


85-86: Validate user presence for audit trail.

The fallback to None when user is not available could lead to missing audit information. Consider if this should be a required field for tracking purposes.

apps/workspaces/apis/export_settings/serializers.py (1)

138-138: LGTM: Comprehensive user tracking implementation.

User context is consistently passed to all relevant update operations: WorkspaceGeneralSettings, MappingSetting, ExpenseGroupSettings, and GeneralMapping.

Also applies to: 155-155, 189-189, 197-197

apps/fyle/models.py (1)

15-15: LGTM! Import statement is correctly placed.

The import of AutoAddCreateUpdateInfoMixin aligns with the PR objective of adding user tracking capabilities.

Comment on lines +2661 to +2664
163 fyle 0023_auto_20250108_0817 2025-01-08 08:25:48.031084+00
164 fyle_accounting_mappings 0028_auto_20241226_1030 2025-01-08 08:25:48.168713+00
165 mappings 0007_auto_20250108_0817 2025-01-08 08:25:48.412455+00
166 workspaces 0042_auto_20250108_0817 2025-01-08 08:25:48.561072+00
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix future-dated migrations.

The migration timestamps are dated in 2025, which is in the future. This could cause issues with migration ordering when new migrations are added.

Update the migration timestamps to use the current date (January 2024) instead of January 2025.

Comment on lines +4860 to +4861
COPY public.expense_group_settings (id, reimbursable_expense_group_fields, corporate_credit_card_expense_group_fields, expense_state, reimbursable_export_date_type, created_at, updated_at, workspace_id, ccc_export_date_type, ccc_expense_state, reimbursable_expense_state, import_card_credits, split_expense_grouping, created_by, updated_by) FROM stdin;
1 {employee_email,report_id,claim_number,fund_source} {report_id,fund_source,employee_email,claim_number,expense_id} PAYMENT_PROCESSING current_date 2022-08-02 20:24:42.329794+00 2022-08-02 20:25:24.6873+00 1 spent_at PAYMENT_PROCESSING PAYMENT_PROCESSING t MULTIPLE_LINE_ITEM \N \N
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Document the data population strategy and ensure consistent test coverage

The codebase shows inconsistent approaches to audit column values in test fixtures:

  • Some test files use email addresses (e.g., in test_fyle/fixtures.py)
  • The reset_db.sql uses NULL values without documentation

Recommendations:

  • Document why NULL values are used in reset_db.sql fixtures
  • Consider aligning the approach across all test fixtures
  • Add test cases that explicitly verify the behavior with both NULL and non-NULL audit values
🔗 Analysis chain

Document the data population strategy.

The fixture data shows NULL values for the new audit columns. Consider:

  1. Documenting why test data uses NULL values
  2. Adding test cases with non-NULL values to verify audit tracking

Let me check if there are corresponding test files that verify the audit tracking functionality:

Also applies to: 4932-4933, 4957-4963, 5088-5089

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for test files that might verify the audit columns
rg -l "created_by|updated_by" "tests/"

Length of output: 150


Script:

#!/bin/bash
# Check content of test files for audit column testing
echo "=== test_fyle/fixtures.py ==="
rg -A 5 -B 5 "created_by|updated_by" "tests/test_fyle/fixtures.py" || true

echo -e "\n=== test_workspaces/fixtures.py ==="
rg -A 5 -B 5 "created_by|updated_by" "tests/test_workspaces/fixtures.py" || true

# Look for any documentation about data strategy
echo -e "\n=== Looking for documentation ==="
rg -A 5 -B 5 "NULL.*created_by|NULL.*updated_by" "tests/" || true

Length of output: 1304

@ashwin1111 ashwin1111 requested a review from ruuushhh January 8, 2025 08:40
@Ashutosh619-sudo Ashutosh619-sudo merged commit 2641e26 into master Jan 13, 2025
2 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jan 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants