Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/snapshot improvement #961

Closed

Conversation

yashgoyal0110
Copy link
Contributor

@yashgoyal0110 yashgoyal0110 commented Feb 28, 2025

fixes: #915

Summary by CodeRabbit

  • New Features

    • Enhanced the admin interface to display and search snapshots by title and key.
    • Expanded GraphQL support with new capabilities to query snapshot details and recent snapshots.
    • Updated snapshot records with additional attributes and automated key assignment.
  • Tests

    • Added tests to ensure the correct handling and display of the new snapshot attributes.

@yashgoyal0110
Copy link
Contributor Author

@arkid15r I have created this PR, do let me know for any changes

Copy link

coderabbitai bot commented Mar 1, 2025

Walkthrough

This changeset enhances the Snapshot functionality across the project. In the Django admin, the Snapshot view now exposes additional fields for display and search. The Snapshot model is updated to include new attributes with a custom save behavior, accompanied by migration updates. New GraphQL types and queries have been added to enable snapshot retrieval and listing, and the API has been extended in the frontend. Finally, tests have been updated to validate the new attributes.

Changes

File(s) Change Summary
backend/apps/owasp/admin.py Added "title" to list_display and added "title" and "key" to search_fields in the SnapshotAdmin class.
backend/apps/owasp/graphql/nodes/snapshot.py, backend/apps/owasp/graphql/queries/snapshot.py, backend/apps/owasp/graphql/queries/__init__.py, frontend/src/api/queries/snapshotQueries.ts Introduced new GraphQL components: a SnapshotNode to expose snapshot fields and a SnapshotQuery (with resolvers for single and recent snapshots). The main query class now inherits from SnapshotQuery and the frontend gains the GET_SNAPSHOT_DETAILS query.
backend/apps/owasp/migrations/0015_snapshot.py, backend/apps/owasp/models/snapshot.py Enhanced the Snapshot model with new fields: "title", "key", "created_at", and "updated_at". Added a custom save method to auto-populate "key". Migration dependency has also been updated.
backend/tests/owasp/models/snapshot_test.py Updated tests to validate that the new title and key attributes in the snapshot mock are correctly assigned.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Frontend
    participant GraphQL_API
    participant SnapshotQuery
    participant SnapshotNode
    participant Database

    Client->>Frontend: Request snapshot details
    Frontend->>GraphQL_API: Execute GET_SNAPSHOT_DETAILS query (with key)
    GraphQL_API->>SnapshotQuery: Forward query for snapshot data
    SnapshotQuery->>SnapshotNode: Invoke resolver (resolve_snapshot or resolve_recent_snapshots)
    SnapshotNode->>Database: Query Snapshot model for data
    Database-->>SnapshotNode: Return snapshot details
    SnapshotNode-->>SnapshotQuery: Provide resolved data
    SnapshotQuery-->>GraphQL_API: Send snapshot data
    GraphQL_API-->>Frontend: Return GraphQL response
    Frontend-->>Client: Display snapshot details
Loading

Poem

I'm a bouncy rabbit, coding with delight,
Hopping through snapshots from morning to night.
Titles and keys now prance in the code,
GraphQL sings as data is showed.
I nibble on changes, so crisp and so new,
Happy hops in a field of code—a dream come true! 🐇✨

✨ 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.
    • 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.
  • @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

sonarqubecloud bot commented Mar 1, 2025

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

🧹 Nitpick comments (6)
frontend/src/api/queries/snapshotQueries.ts (1)

3-40: Well-structured GraphQL query for snapshot details.

The query is well-organized and includes all necessary fields including the new title and key attributes. The nested data for newReleases, newProjects, and newChapters is comprehensive.

Consider adding a comment describing the purpose of this query and potentially using GraphQL fragments if this structure will be reused elsewhere in the application.

 import { gql } from '@apollo/client'

+/**
+ * Query to fetch detailed information about a snapshot by its key.
+ * Returns the snapshot with its basic attributes and nested entities (releases, projects, chapters).
+ */
 export const GET_SNAPSHOT_DETAILS = gql`
   query GetSnapshotDetails($key: String!) {
     snapshot(key: $key) {
backend/apps/owasp/graphql/nodes/snapshot.py (1)

13-16: Consider defining constants in a central location

These limits for recent items are well defined, but they might be better placed in a central configuration file or settings module if they need to be reused across multiple components.

backend/apps/owasp/models/snapshot.py (2)

38-42: Add validation for key format

While the save method automatically sets the key in YYYY-mm format, consider adding validation to ensure manual entries follow this format too.

def save(self, *args, **kwargs):
    """Automatically set the key in YYYY-mm format before saving."""
    if not self.key:
        self.key = now().strftime("%Y-%m")
+   else:
+       # Validate key format (YYYY-mm)
+       import re
+       if not re.match(r"^\d{4}-\d{2}$", self.key):
+           raise ValueError("Key must be in YYYY-mm format")
    super().save(*args, **kwargs)

44-46: Update string representation to include new fields

Since you've added title and key fields, consider updating the str method to include them for better identification.

def __str__(self):
    """Return a string representation of the snapshot."""
-   return f"Snapshot {self.start_at} to {self.end_at} ({self.status})"
+   return f"Snapshot {self.key}: {self.title or 'Untitled'} ({self.status})"
backend/apps/owasp/graphql/queries/snapshot.py (2)

23-29: Improve exception handling

Consider catching the specific DoesNotExist exception rather than a broad try-except block to avoid masking other potential exceptions.

def resolve_snapshot(root, info, key):
    """Resolve snapshot by key."""
    try:
        return Snapshot.objects.get(key=key)
-   except Snapshot.DoesNotExist:
+   except Snapshot.DoesNotExist as e:
+       # Log the exception if needed
+       # logger.debug(f"Snapshot with key {key} not found: {e}")
        return None
+   # Let other exceptions propagate to be handled by the GraphQL error handler

30-32: Consider adding pagination for recent_snapshots

For future scalability, consider implementing cursor-based pagination for the recent_snapshots query, especially if the number of snapshots grows significantly.

-recent_snapshots = graphene.List(
-    SnapshotNode,
-    limit=graphene.Int(default_value=8),
-)

+from graphene_django.filter import DjangoFilterConnectionField
+
+# Add connection to SnapshotNode class in nodes/snapshot.py
+# class SnapshotNode(GenericEntityNode):
+#     class Meta:
+#         interfaces = (graphene.relay.Node,)
+
+recent_snapshots = DjangoFilterConnectionField(
+    SnapshotNode,
+    first=graphene.Int(default_value=8),
+    orderBy=graphene.String(default_value="-created_at")
+)

def resolve_recent_snapshots(root, info, limit):
    """Resolve recent snapshots."""
    return Snapshot.objects.order_by("-created_at")[:limit]
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 126b0b1 and 73bf682.

📒 Files selected for processing (8)
  • backend/apps/owasp/admin.py (2 hunks)
  • backend/apps/owasp/graphql/nodes/snapshot.py (1 hunks)
  • backend/apps/owasp/graphql/queries/__init__.py (1 hunks)
  • backend/apps/owasp/graphql/queries/snapshot.py (1 hunks)
  • backend/apps/owasp/migrations/0015_snapshot.py (2 hunks)
  • backend/apps/owasp/models/snapshot.py (3 hunks)
  • backend/tests/owasp/models/snapshot_test.py (2 hunks)
  • frontend/src/api/queries/snapshotQueries.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: CodeQL (python)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: Run backend tests
🔇 Additional comments (15)
backend/tests/owasp/models/snapshot_test.py (2)

15-16: Good addition of test attributes for snapshot model.

These new attributes align with the Snapshot model updates, providing necessary test data for the new fields.


33-36: Well-structured test for new attributes.

This test method properly validates the new title and key attributes, with a clear docstring explaining its purpose. Good practice to explicitly test newly added model attributes.

backend/apps/owasp/admin.py (2)

122-122: Good UI enhancement for admin view.

Adding the title field to list_display provides better visibility of snapshots in the admin interface.


136-137: Improved searchability for snapshot administration.

Adding title and key to search_fields enhances admin usability by allowing administrators to quickly find snapshots by these new attributes.

backend/apps/owasp/graphql/queries/__init__.py (2)

6-6: Appropriate import of new SnapshotQuery.

The import statement is correctly added to bring in the new query functionality.


10-10: Properly integrated SnapshotQuery into OwaspQuery.

The inheritance hierarchy is correctly extended to include the new SnapshotQuery, making snapshot data available through the GraphQL API.

backend/apps/owasp/graphql/nodes/snapshot.py (3)

19-30: GraphQL node structure looks good

The SnapshotNode class is well-structured with appropriate field definitions for exposing the Snapshot model data through GraphQL.


65-68:

❓ Verification inconclusive

Ensure published_at field is indexed

Similar to the created_at index concern, verify that published_at is indexed for optimal performance when ordering releases.


🏁 Script executed:

#!/bin/bash
# Check if indexes exist on the published_at field for releases
echo "Checking for indexes on releases table..."
python -c "
from django.db import connection
from apps.github.models.release import Release

table_name = Release._meta.db_table

# Check for existing indexes
with connection.cursor() as cursor:
    cursor.execute(f\"\"\"
    SELECT indexname, indexdef 
    FROM pg_indexes 
    WHERE tablename = '{table_name}'
    \"\"\")
    indexes = cursor.fetchall()
    
    has_published_at_index = any('published_at' in idx[1] for idx in indexes)
    
    if has_published_at_index:
        print(f'Index on published_at exists for table {table_name}')
    else:
        print(f'No index found on published_at for table {table_name}')
        print('Consider adding an index with:')
        print(f'CREATE INDEX idx_{table_name}_published_at ON {table_name} (published_at);')
"

Length of output: 1014


Action: Verify that the published_at field is indexed

The automated check failed because Django isn’t available in the current environment, so manual verification in your Django setup is required. Please ensure that the releases table has an index on the published_at column. If no such index exists, consider adding one—for example:

  • Location: backend/apps/owasp/graphql/nodes/snapshot.py (used in ordering new releases)
  • Recommendation: Confirm that the database table for releases includes an index on the published_at field. If it does not, add an index using a command similar to:
    CREATE INDEX idx_<table_name>_published_at ON <table_name> (published_at);
    

57-60:

❓ Verification inconclusive

Verify query performance for large datasets

The ordering by created_at with a limit could potentially cause performance issues with large datasets. Consider adding database indexes on the created_at field if they don't already exist.


🏁 Script executed:

#!/bin/bash
# Check if indexes exist on the created_at field
echo "Checking for indexes on new_issues related table..."
python -c "
from django.db import connection
from apps.owasp.models.snapshot import Snapshot

# Get the related model for new_issues
related_model = Snapshot.new_issues.field.model
table_name = related_model._meta.db_table

# Check for existing indexes
with connection.cursor() as cursor:
    cursor.execute(f\"\"\"
    SELECT indexname, indexdef 
    FROM pg_indexes 
    WHERE tablename = '{table_name}'
    \"\"\")
    indexes = cursor.fetchall()
    
    has_created_at_index = any('created_at' in idx[1] for idx in indexes)
    
    if has_created_at_index:
        print(f'Index on created_at exists for table {table_name}')
    else:
        print(f'No index found on created_at for table {table_name}')
        print('Consider adding an index with:')
        print(f'CREATE INDEX idx_{table_name}_created_at ON {table_name} (created_at);')
"

Length of output: 1114


Action Required: Manually Verify Index on the created_at Field

The current implementation orders new_issues by created_at with a limit, which can lead to performance issues on large datasets if the underlying column isn’t indexed. The automated check failed due to a missing Django module, so please verify manually that:

  • The related model for new_issues defines created_at with an index (e.g., via db_index=True or through a customized Meta index).
  • If the index is missing, consider adding one to improve query performance:
    CREATE INDEX idx_<table_name>_created_at ON <table_name> (created_at);
    
backend/apps/owasp/models/snapshot.py (2)

20-21: The new fields enhance model identification

Adding title and key fields improves the model's usability and identification capabilities.


40-41:

❓ Verification inconclusive

Consider collision handling for identical keys

Since keys are generated based on the month (YYYY-mm), multiple snapshots created in the same month would cause uniqueness conflicts.


🏁 Script executed:

#!/bin/bash
# Verify if there's a possibility of multiple snapshots per month
python -c "
from apps.owasp.models.snapshot import Snapshot
from django.db.models import Count
from django.db.models.functions import TruncMonth
from django.utils.timezone import now
import datetime

# Check if there are any snapshots in the system
snapshot_count = Snapshot.objects.count()
print(f'Total snapshots in system: {snapshot_count}')

# Check frequency of snapshot creation
if snapshot_count > 0:
    # Get first and last snapshot
    first = Snapshot.objects.order_by('created_at').first()
    last = Snapshot.objects.order_by('-created_at').first()
    
    # Calculate months between
    months_between = (last.created_at.year - first.created_at.year) * 12 + \
                     (last.created_at.month - first.created_at.month) + 1
    
    if months_between > 0:
        avg_per_month = snapshot_count / months_between
        print(f'Average snapshots per month: {avg_per_month:.2f}')
        
        if avg_per_month > 1:
            print('POTENTIAL ISSUE: You are averaging more than one snapshot per month.')
            print('Consider extending the key format to include day or sequential number.')
    else:
        print('All snapshots were created in the same month')

# Check for any existing key conflicts
today = now().strftime('%Y-%m')
month_snapshots = Snapshot.objects.filter(key=today).count()
print(f'Snapshots with current month key ({today}): {month_snapshots}')
"

Length of output: 1575


Action Required: Review Snapshot Key Collision Handling

It appears that the current verification script failed (ModuleNotFoundError) due to a module path issue. Please adjust the environment by setting the PYTHONPATH (e.g., to "backend") before running the verification. In the meantime, note that generating keys solely based on the month (YYYY-mm) could cause collisions if more than one snapshot is created in the same month. Consider extending the key format (by including the day or a sequential number) or implementing collision resolution to avoid key conflicts.

  • Verify that your environment is correctly configured (e.g., using PYTHONPATH=backend) so that the modules can be imported.
  • Manually test or re-run a modified verification script with the correct PYTHONPATH to assess if multiple snapshots per month occur.
  • If collisions are detected, update the key-generation logic to ensure uniqueness.
backend/apps/owasp/graphql/queries/snapshot.py (1)

13-21: Well-structured GraphQL query fields

The snapshot and recent_snapshots fields are well defined with appropriate parameters.

backend/apps/owasp/migrations/0015_snapshot.py (3)

8-8: Dependency update looks good

The update to the GitHub dependency from version 0015 to 0016 is correctly reflected.


22-25: New fields are properly defined

The new title, key, created_at, and updated_at fields are properly defined in the migration with appropriate constraints.


23-23:

❓ Verification inconclusive

Verify database field constraint for key format

Since the key field has a specific format requirement (YYYY-mm), consider adding a database-level constraint to enforce this format.


🏁 Script executed:

#!/bin/bash
# Check if PostgreSQL is being used and if so, suggest a check constraint
echo "Checking database backend and suggesting constraint improvements..."
python -c "
from django.db import connection
from django.conf import settings

# Check if PostgreSQL is being used
db_engine = settings.DATABASES['default']['ENGINE']
is_postgresql = 'postgresql' in db_engine

if is_postgresql:
    print('PostgreSQL detected. You could add a check constraint:')
    print('ALTER TABLE owasp_snapshots ADD CONSTRAINT key_format_check CHECK (key ~ \'^\d{4}-\d{2}$\');')
else:
    print(f'Database engine: {db_engine}')
    print('Format validation should be handled in application code only.')
"

Length of output: 842


Action: Verify and Enforce Key Format Constraint

The key field is intended to follow the "YYYY-mm" format. If your database backend is PostgreSQL, consider adding a check constraint to enforce this directly at the database level. For example, you could use the following SQL statement:

ALTER TABLE owasp_snapshots
ADD CONSTRAINT key_format_check
CHECK (key ~ '^\d{4}-\d{2}$');

Note: The verification script we attempted encountered a ModuleNotFoundError (missing Django), likely because it was run in an environment without Django installed. Please ensure that you run these tests in an environment where Django is available or manually verify your database engine via your Django settings. Once you confirm that PostgreSQL is used, implement the check constraint in a migration to enforce the correct key format.

@yashgoyal0110 yashgoyal0110 closed this by deleting the head repository Mar 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

OWASP Snapshot Improvement
2 participants