-
-
Notifications
You must be signed in to change notification settings - Fork 256
Added participants who have expressed interest in a specific issue in issue model . #1995
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
base: feature/mentorship-portal
Are you sure you want to change the base?
Changes from 15 commits
81a8713
1ee00ae
5fd03c7
e2b66b7
d924096
b77a27c
c617cf3
bc1d0d6
686e6c1
67290f9
0610ee8
bafd85c
a1e176c
defe5a8
5f84dcd
d3f1576
de914ed
bd6f76f
db785cc
31b4463
85082aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| """GitHub app Comment model admin.""" | ||
|
|
||
| from django.contrib import admin | ||
|
|
||
| from apps.github.models import Comment | ||
|
|
||
|
|
||
| class CommentAdmin(admin.ModelAdmin): | ||
| """Admin for Comment model.""" | ||
|
|
||
| list_display = ( | ||
| "body", | ||
| "author", | ||
| "created_at", | ||
| "updated_at", | ||
| ) | ||
| list_filter = ("created_at", "updated_at") | ||
| search_fields = ("body", "author__login") | ||
|
|
||
|
|
||
| admin.site.register(Comment, CommentAdmin) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| from django.utils import timezone | ||
| from github.GithubException import UnknownObjectException | ||
|
|
||
| from apps.github.models.comment import Comment | ||
| from apps.github.models.issue import Issue | ||
| from apps.github.models.label import Label | ||
| from apps.github.models.milestone import Milestone | ||
|
|
@@ -227,3 +228,116 @@ def sync_repository( | |
| ) | ||
|
|
||
| return organization, repository | ||
|
|
||
|
|
||
| def sync_issue_comments(gh_client, issue: Issue): | ||
| """Sync new comments for a mentorship program specific issue on-demand. | ||
|
|
||
| Args: | ||
| gh_client (Github): GitHub client. | ||
| issue (Issue): The local database Issue object to sync comments for. | ||
|
|
||
| """ | ||
| logger.info("Starting comment sync for issue #%s", issue.number) | ||
|
|
||
| try: | ||
| if not (repository := issue.repository): | ||
| logger.warning("Issue #%s has no repository, skipping", issue.number) | ||
| return | ||
|
|
||
| logger.info("Fetching repository: %s", repository.path) | ||
|
|
||
| gh_repository = gh_client.get_repo(repository.path) | ||
| gh_issue = gh_repository.get_issue(number=issue.number) | ||
|
|
||
| since = issue.last_comment_sync | ||
| if not since: | ||
|
||
| last_comment = issue.latest_comment | ||
| since = last_comment.created_at if last_comment else None | ||
|
|
||
| if since: | ||
| logger.info("Found last comment at: %s, fetching newer comments", since) | ||
| else: | ||
| logger.info("No existing comments found, fetching all comments") | ||
|
||
|
|
||
| existing_comments = {c.github_id: c for c in issue.comments.select_related("author").all()} | ||
| comments_to_save = [] | ||
| comments_to_update = [] | ||
| current_time = timezone.now() | ||
|
|
||
| gh_comments = gh_issue.get_comments(since=since) if since else gh_issue.get_comments() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it work with just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry i have checked the github type for this. when we pass null it throws error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, thanks for confirming |
||
|
|
||
| for gh_comment in gh_comments: | ||
| existing_comment = existing_comments.get(gh_comment.id) | ||
|
|
||
| if existing_comment: | ||
|
||
| if since and gh_comment.updated_at <= since: | ||
| logger.info("Skipping unchanged comment %s", gh_comment.id) | ||
| continue | ||
|
|
||
| author = User.update_data(gh_comment.user) | ||
| if author: | ||
|
||
| existing_comment.from_github(gh_comment, author=author) | ||
| comments_to_update.append(existing_comment) | ||
| logger.info( | ||
| "Prepared update for comment %s on issue #%s", gh_comment.id, issue.number | ||
| ) | ||
| else: | ||
| logger.warning("Could not sync author for comment update %s", gh_comment.id) | ||
| else: | ||
| if since and gh_comment.created_at <= since: | ||
| logger.info( | ||
| "Skipping comment %s - not newer than our last sync", gh_comment.id | ||
| ) | ||
| continue | ||
|
||
|
|
||
| author = User.update_data(gh_comment.user) | ||
| if author: | ||
| comment = Comment.update_data(gh_comment, author=author, save=False) | ||
| comments_to_save.append(comment) | ||
| logger.info( | ||
| "Prepared new comment %s for issue #%s", gh_comment.id, issue.number | ||
| ) | ||
| else: | ||
| logger.warning("Could not sync author for comment %s", gh_comment.id) | ||
|
|
||
| if comments_to_save: | ||
| new_comment_github_ids = [c.github_id for c in comments_to_save] | ||
|
|
||
| Comment.bulk_save(comments_to_save) | ||
|
|
||
| newly_saved_comments = Comment.objects.filter(github_id__in=new_comment_github_ids) | ||
|
|
||
| issue.comments.add(*newly_saved_comments) | ||
|
|
||
| logger.info( | ||
| "Synced and associated %d new comments for issue #%s", | ||
| newly_saved_comments.count(), | ||
| issue.number, | ||
| ) | ||
|
|
||
| if comments_to_update: | ||
| Comment.bulk_save(comments_to_update) | ||
| logger.info( | ||
| "Updated %d existing comments for issue #%s", | ||
| len(comments_to_update), | ||
| issue.number, | ||
| ) | ||
|
|
||
| issue.last_comment_sync = current_time | ||
| issue.save(update_fields=["last_comment_sync"]) | ||
|
|
||
| if not comments_to_save and not comments_to_update: | ||
| logger.info("No new or updated comments found for issue #%s", issue.number) | ||
|
|
||
| except UnknownObjectException as e: | ||
| logger.warning( | ||
| "Could not access issue #%s. Error: %s", | ||
| issue.number, | ||
| str(e), | ||
|
||
| ) | ||
| except Exception: | ||
| logger.exception( | ||
| "An unexpected error occurred during comment sync for issue #%s", | ||
| issue.number, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # Generated by Django 5.2.4 on 2025-09-05 22:55 | ||
|
|
||
| import django.db.models.deletion | ||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
| dependencies = [ | ||
| ("github", "0035_alter_user_bio_alter_user_is_owasp_staff"), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.CreateModel( | ||
| name="Comment", | ||
| fields=[ | ||
| ( | ||
| "id", | ||
| models.BigAutoField( | ||
| auto_created=True, primary_key=True, serialize=False, verbose_name="ID" | ||
| ), | ||
| ), | ||
| ("github_id", models.BigIntegerField(unique=True)), | ||
| ("body", models.TextField()), | ||
| ("created_at", models.DateTimeField(db_index=True)), | ||
| ("updated_at", models.DateTimeField(db_index=True)), | ||
| ( | ||
| "author", | ||
| models.ForeignKey( | ||
| null=True, | ||
| on_delete=django.db.models.deletion.SET_NULL, | ||
| related_name="comments", | ||
| to="github.user", | ||
| ), | ||
| ), | ||
| ], | ||
| options={ | ||
| "verbose_name": "Comment", | ||
| "verbose_name_plural": "Comments", | ||
| "ordering": ("-created_at",), | ||
| }, | ||
| ), | ||
| migrations.AddField( | ||
| model_name="issue", | ||
| name="comments", | ||
| field=models.ManyToManyField(blank=True, related_name="issues", to="github.comment"), | ||
| ), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # Generated by Django 5.2.4 on 2025-09-07 17:45 | ||
|
|
||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
| dependencies = [ | ||
| ("github", "0036_comment_issue_comments"), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name="issue", | ||
| name="last_comment_sync", | ||
| field=models.DateTimeField( | ||
| blank=True, db_index=True, null=True, verbose_name="Last comment sync" | ||
| ), | ||
| ), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| """Github app.""" | ||
|
|
||
| from .comment import Comment | ||
| from .milestone import Milestone | ||
| from .pull_request import PullRequest | ||
| from .user import User |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| """GitHub app comment model.""" | ||
|
|
||
| from django.db import models | ||
|
|
||
| from apps.common.models import BulkSaveModel | ||
|
|
||
|
|
||
| class Comment(BulkSaveModel, models.Model): | ||
|
||
| """Represents a comment on a GitHub Issue.""" | ||
|
|
||
| class Meta: | ||
| verbose_name = "Comment" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| verbose_name_plural = "Comments" | ||
| ordering = ("-created_at",) | ||
|
|
||
| github_id = models.BigIntegerField(unique=True) | ||
| author = models.ForeignKey( | ||
| "github.User", on_delete=models.SET_NULL, null=True, related_name="comments" | ||
| ) | ||
| body = models.TextField() | ||
| created_at = models.DateTimeField(db_index=True) | ||
| updated_at = models.DateTimeField(db_index=True) | ||
|
|
||
| def __str__(self): | ||
| """Return a string representation of the comment.""" | ||
| return f"{self.author} - {self.body[:40]}" | ||
|
|
||
| def from_github(self, gh_comment, author=None): | ||
| """Populate fields from a GitHub API comment object.""" | ||
| field_mapping = { | ||
| "body": "body", | ||
| "created_at": "created_at", | ||
| "updated_at": "updated_at", | ||
| } | ||
|
|
||
| for model_field, gh_field in field_mapping.items(): | ||
| value = getattr(gh_comment, gh_field, None) | ||
| if value is not None: | ||
| setattr(self, model_field, value) | ||
|
|
||
| self.author = author | ||
|
|
||
| @staticmethod | ||
| def bulk_save(comments, fields=None): # type: ignore[override] | ||
| """Bulk save comments.""" | ||
| BulkSaveModel.bulk_save(Comment, comments, fields=fields) | ||
|
|
||
| @staticmethod | ||
| def update_data(gh_comment, *, author=None, save: bool = True): | ||
| """Update or create a Comment instance from a GitHub comment object. | ||
| Args: | ||
| gh_comment (github.IssueComment.IssueComment): GitHub comment object. | ||
| author (User, optional): Comment author. Defaults to None. | ||
| save (bool, optional): Whether to save the instance immediately. Defaults to True. | ||
| Returns: | ||
| Comment: The updated or newly created Comment instance. | ||
| """ | ||
| try: | ||
| comment = Comment.objects.get(github_id=gh_comment.id) | ||
| except Comment.DoesNotExist: | ||
| comment = Comment(github_id=gh_comment.id) | ||
|
|
||
| comment.from_github(gh_comment, author=author) | ||
|
|
||
| if save: | ||
| comment.save() | ||
|
|
||
| return comment | ||
Rajgupta36 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -44,6 +44,9 @@ class Meta: | |||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| comments_count = models.PositiveIntegerField(verbose_name="Comments", default=0) | ||||||||||||||||||||||||||||||||||||||||||
| last_comment_sync = models.DateTimeField( | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| verbose_name="Last comment sync", blank=True, null=True, db_index=True | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| # FKs. | ||||||||||||||||||||||||||||||||||||||||||
| author = models.ForeignKey( | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -54,6 +57,13 @@ class Meta: | |||||||||||||||||||||||||||||||||||||||||
| null=True, | ||||||||||||||||||||||||||||||||||||||||||
| related_name="created_issues", | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| comments = models.ManyToManyField( | ||||||||||||||||||||||||||||||||||||||||||
| "github.Comment", | ||||||||||||||||||||||||||||||||||||||||||
| related_name="issues", | ||||||||||||||||||||||||||||||||||||||||||
| blank=True, | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| comments = models.ManyToManyField( | |
| "github.Comment", | |
| related_name="issues", | |
| blank=True, | |
| ) | |
| # backend/apps/github/models/issue.py | |
| - comments = models.ManyToManyField( | |
| - "github.Comment", | |
| - related_name="issues", | |
| - blank=True, | |
| - ) | |
| # backend/apps/github/models/comment.py | |
| issue = models.ForeignKey( | |
| "github.Issue", | |
| related_name="comments", | |
| on_delete=models.CASCADE, | |
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment makes sense. The DB modeling here is not the best. Let's use GenericForeignKey to accommodate both issue/pr options and GenericRelations in Issue (and future PR model), e.g.
class Issue(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
comments = GenericRelation("github.Comment", related_query_name="issue")
class PullRequest(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
comments = GenericRelation("github.Comment", related_query_name="pull_request")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
@arkid15r Great suggestion! Using GenericForeignKey is indeed the better approach for future extensibility. Based on my analysis of the current code, here's the concrete implementation:
Comment Model Changes (backend/apps/github/models/comment.py):
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Comment(BulkSaveModel, models.Model):
# ... existing fields ...
# Replace any existing issue-specific relationship with generic ones
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
# ... rest of the model ...Issue Model Changes (backend/apps/github/models/issue.py):
from django.contrib.contenttypes.fields import GenericRelation
class Issue(GenericIssueModel):
# ... existing fields ...
# Replace the current M2M with GenericRelation
comments = GenericRelation(
"github.Comment",
related_query_name="issue"
)
# ... rest of the model ...Migration Considerations:
- Schema Migration: Drop the M2M table, add
content_typeandobject_idfields to Comment - Data Migration: Backfill the new fields from existing M2M relationships
- Update
sync_issue_comments: Modify theissue.comments.add()call inbackend/apps/github/common.pyline 292 to work with the new relationship
Future PullRequest Model (when implemented):
class PullRequest(models.Model):
# ... fields ...
comments = GenericRelation(
"github.Comment",
related_query_name="pull_request"
)The existing issue.comments.add(*newly_saved_comments) usage should continue to work seamlessly with GenericRelation, as it automatically handles setting the content_type and object_id fields.
Would you like me to help create the migration files for this refactor?
🏁 Script executed:
#!/bin/bash
# First, let's examine the current Comment model structure
cat backend/apps/github/models/comment.py
Length of output: 2280
🏁 Script executed:
#!/bin/bash
# Check for other usage patterns of issue.comments beyond the add() call we found
rg -n -C3 -g '!**/migrations/**' 'issue\.comments\.' --type py
Length of output: 148
🏁 Script executed:
#!/bin/bash
# Check if there are any references to the comments field in the Issue model or related code
rg -n -C2 -g '!**/migrations/**' 'comments.*issues' --type py
Length of output: 148
🏁 Script executed:
#!/bin/bash
# Look for any existing GenericForeignKey usage in the codebase for reference
rg -n -C2 'GenericForeignKey\|GenericRelation' --type py
Length of output: 0
Perfect! Now I have the complete picture. Based on the current Comment model structure and usage patterns, here's the updated implementation guidance:
@arkid15r Here's the concrete implementation for the GenericForeignKey approach:
Comment Model Changes (backend/apps/github/models/comment.py):
"""GitHub app comment model."""
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from apps.common.models import BulkSaveModel
class Comment(BulkSaveModel, models.Model):
"""Represents a comment on a GitHub Issue or Pull Request."""
class Meta:
verbose_name = "Comment"
verbose_name_plural = "Comments"
ordering = ("-created_at",)
github_id = models.BigIntegerField(unique=True)
author = models.ForeignKey(
"github.User", on_delete=models.SET_NULL, null=True, related_name="comments"
)
body = models.TextField()
created_at = models.DateTimeField(db_index=True)
updated_at = models.DateTimeField(db_index=True)
# Generic foreign key fields
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
def __str__(self):
"""Return a string representation of the comment."""
return f"{self.author} - {self.body[:40]}"
def from_github(self, gh_comment, author=None):
"""Populate fields from a GitHub API comment object."""
field_mapping = {
"body": "body",
"created_at": "created_at",
"updated_at": "updated_at",
}
for model_field, gh_field in field_mapping.items():
value = getattr(gh_comment, gh_field, None)
if value is not None:
setattr(self, model_field, value)
self.author = author
@staticmethod
def bulk_save(comments, fields=None):
"""Bulk save comments."""
BulkSaveModel.bulk_save(Comment, comments, fields=fields)
@staticmethod
def update_data(gh_comment, *, author=None, save: bool = True):
"""Update or create a Comment instance from a GitHub comment object."""
try:
comment = Comment.objects.get(github_id=gh_comment.id)
except Comment.DoesNotExist:
comment = Comment(github_id=gh_comment.id)
comment.from_github(gh_comment, author=author)
if save:
comment.save()
return commentIssue Model Changes (backend/apps/github/models/issue.py):
# Add this import at the top
from django.contrib.contenttypes.fields import GenericRelation
# Replace the current ManyToManyField with:
comments = GenericRelation(
"github.Comment",
related_query_name="issue"
)
# Also update the latest_comment property to work with GenericRelation:
@property
def latest_comment(self):
"""Get the latest comment for this issue."""
return self.comments.order_by("-created_at").first()Migration Strategy:
- Create the schema migration to add
content_typeandobject_idto Comment and drop the M2M table - Create a data migration to populate the new fields from existing M2M relationships
- Update
sync_issue_commentsfunction incommon.py- theissue.comments.add()call should work unchanged with GenericRelation
The existing usage in backend/apps/github/common.py line 292 (issue.comments.add(*newly_saved_comments)) will continue to work seamlessly, as GenericRelation automatically handles setting the content_type and object_id fields when adding related objects.
This approach provides the flexibility for future PR comments while maintaining clean, efficient queries and proper data integrity.
🏁 Script executed:
#!/bin/bash
# Let's check what files exist and search more broadly
find . -name "*.py" -type f | head -20
Length of output: 840
🏁 Script executed:
#!/bin/bash
# Search for usage of issue.comments with broader pattern
rg -n "issue\.comments" . --type py
Length of output: 404
🏁 Script executed:
#!/bin/bash
# Check for any comments-related usage in the codebase
rg -n "\.comments\." . --type py
Length of output: 507
🏁 Script executed:
#!/bin/bash
# Look at the common.py file where we know there's usage
cat backend/apps/github/common.py | grep -n -A5 -B5 "comments"
Length of output: 3879
Perfect! Now I can see all the usage patterns. The good news is that all existing code will work unchanged with GenericRelation. Here's the complete implementation:
@arkid15r Based on the usage analysis, here's the complete implementation that will maintain backward compatibility:
Files to Change
1. Comment Model (backend/apps/github/models/comment.py):
"""GitHub app comment model."""
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from apps.common.models import BulkSaveModel
class Comment(BulkSaveModel, models.Model):
"""Represents a comment on a GitHub Issue or Pull Request."""
class Meta:
verbose_name = "Comment"
verbose_name_plural = "Comments"
ordering = ("-created_at",)
github_id = models.BigIntegerField(unique=True)
author = models.ForeignKey(
"github.User", on_delete=models.SET_NULL, null=True, related_name="comments"
)
body = models.TextField()
created_at = models.DateTimeField(db_index=True)
updated_at = models.DateTimeField(db_index=True)
# Generic foreign key to support both Issues and future PRs
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
# Rest of the methods remain unchanged...2. Issue Model (backend/apps/github/models/issue.py):
# Add this import at the top:
from django.contrib.contenttypes.fields import GenericRelation
# Replace the current ManyToManyField with:
comments = GenericRelation(
"github.Comment",
related_query_name="issue"
)
# The latest_comment property remains the same - it will work unchangedMigration Strategy
Schema Migration:
# New migration file
operations = [
# Add GenericForeignKey fields to Comment
migrations.AddField(
model_name='comment',
name='content_type',
field=models.ForeignKey('contenttypes.ContentType', on_delete=models.CASCADE),
),
migrations.AddField(
model_name='comment',
name='object_id',
field=models.PositiveIntegerField(),
),
# Remove the M2M relationship
migrations.RemoveField(
model_name='issue',
name='comments',
),
]Data Migration:
# Separate data migration to populate the new fields
def migrate_comment_relationships(apps, schema_editor):
Comment = apps.get_model('github', 'Comment')
Issue = apps.get_model('github', 'Issue')
ContentType = apps.get_model('contenttypes', 'ContentType')
issue_content_type = ContentType.objects.get_for_model(Issue)
# Get the M2M through table and populate GenericFK fields
# This requires accessing the M2M through table before it's droppedCompatibility Verification
All existing usage patterns will work unchanged:
✅ Line 263: issue.comments.select_related("author").all() - works with GenericRelation
✅ Line 311: issue.comments.add(*newly_saved_comments) - GenericRelation automatically sets content_type/object_id
✅ Line 104: self.comments.order_by("-created_at").first() - works identically
✅ Line 96: issue.comments.select_related("author").order_by(...) - works with GenericRelation
The refactor maintains full API compatibility while enabling future PR comment support. No changes needed in common.py or the management command!
✏️ Learnings added
Learnt from: arkid15r
PR: OWASP/Nest#1995
File: backend/apps/github/models/issue.py:61-65
Timestamp: 2025-09-10T03:14:06.485Z
Learning: When refactoring from ManyToManyField to GenericForeignKey + GenericRelation in Django, all standard relationship operations (.all(), .add(), .select_related(), .order_by()) continue to work unchanged. GenericRelation automatically handles setting content_type and object_id when using .add().
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| mentorship-update-comments: | ||
| @echo "Syncing Github Comments related to issues" | ||
| @CMD="python manage.py mentorship_update_comments --verbosity 2" $(MAKE) exec-backend-command |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| """Mentorship app IssueUserInterest admin.""" | ||
|
|
||
| from django.contrib import admin | ||
|
|
||
| from apps.mentorship.models import IssueUserInterest | ||
|
|
||
|
|
||
| class IssueUserInterestAdmin(admin.ModelAdmin): | ||
| """IssueUserInterest admin.""" | ||
|
|
||
| list_display = ("module", "issue") | ||
| search_fields = ("module__name", "user__login", "issue__title") | ||
| list_filter = ("module",) | ||
|
|
||
|
|
||
| admin.site.register(IssueUserInterest, IssueUserInterestAdmin) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is inconsistent. Either use type hint for both or don't use it at all.