Feat: Add created_by, updated_by to conf tables#421
Conversation
WalkthroughThe 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 Changes
Sequence DiagramsequenceDiagram
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
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
There was a problem hiding this comment.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
apps/workspaces/apis/import_settings/serializers.py (1)
Line range hint
122-122: Passuserto trigger methods to maintain user contextSince the methods
pre_save_workspace_general_settings,post_save_workspace_general_settings,pre_save_mapping_settings, andpost_save_mapping_settingshave been updated to accept theuserparameter, consider passinguser=userwhen calling these methods to ensure that user context is maintained throughout the trigger process.Apply this diff to include
userin 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_byandupdated_byfields 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
EmailFieldinstead ofCharFieldwould 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 similarlytests/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
AutoAddCreateUpdateInfoMixinfor adding user tracking. However, other models in the file (likeWorkspace,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 Nonetests/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:
- Using a fixture to create test user data
- 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:
- Type hint for the
userparameter- 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:
- Split field processing logic into separate methods
- Extract claim number and report ID handling logic
- 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_byandupdated_bycolumns are nullable without default values. Since these columns track audit information:
- Consider making them NOT NULL to ensure data integrity
- 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
📒 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 retrievinguserfrom request contextGood implementation of retrieving the
userfrom the request context, safely handling cases whererequestorusermay not be present.
145-145: PassingusertoWorkspaceGeneralSettings.objects.update_or_createProperly passing
usertoupdate_or_createensures thatcreated_byandupdated_byfields are correctly set.
158-158: PassingusertoGeneralMapping.objects.update_or_createPassing
usertoupdate_or_createmaintains consistency in tracking user actions during updates.
211-211: PassingusertoMappingSetting.objects.update_or_createEnsures 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:
- Confirm that the fields being nullable won't cause issues with existing queries
- 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.pyLength 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
WorkspaceGeneralSettingsandGeneralMappingupdate operations.Also applies to: 128-128
85-86: Validate user presence for audit trail.The fallback to
Nonewhen 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
AutoAddCreateUpdateInfoMixinaligns with the PR objective of adding user tracking capabilities.
| 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 |
There was a problem hiding this comment.
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.
| 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 |
There was a problem hiding this comment.
💡 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:
- Documenting why test data uses NULL values
- 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
https://app.clickup.com/1864988/v/l/6-901605343641-1