-
-
Notifications
You must be signed in to change notification settings - Fork 234
Added TaskLevel Model #1819
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
Added TaskLevel Model #1819
Conversation
Summary by CodeRabbit
WalkthroughThis change introduces a new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15–20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes were identified. Possibly related PRs
Suggested reviewers
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
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.
Actionable comments posted: 5
🧹 Nitpick comments (7)
backend/apps/mentorship/admin.py (1)
112-126
: Consider adding list filters to TaskLevelAdmin.The admin class is functional but could benefit from list filters to improve the admin user experience.
class TaskLevelAdmin(admin.ModelAdmin): """Admin view for TaskLevel model.""" list_display = ( "description", "github_labels", "module", "name", ) search_fields = ( "name", "module__name", ) + + list_filter = ("module",)backend/apps/mentorship/models/common/status.py (1)
1-1
: Fix incorrect docstring.The docstring mentions "start/end range" which is incorrect for a Status model. This appears to be copied from another file.
-"""Mentorship app start/end range.""" +"""Mentorship app status model."""backend/apps/mentorship/models/tasl_level.py (2)
22-26
: Consider validating the github_labels structure.The
github_labels
field uses a generic JSONField withdefault=list
, but there's no validation to ensure the stored data maintains the expected list structure or contains valid label data.Consider adding a custom validator:
+from django.core.exceptions import ValidationError +def validate_github_labels(value): + """Validate that github_labels is a list of strings or objects.""" + if not isinstance(value, list): + raise ValidationError("GitHub labels must be a list.") + for label in value: + if not isinstance(label, (str, dict)): + raise ValidationError("Each label must be a string or dictionary.") github_labels = models.JSONField( default=list, blank=True, verbose_name="GitHub Labels", + validators=[validate_github_labels], )
50-57
: Handle potential attribute errors in str method.The
__str__
method assumesself.module
andself.module.name
are always available, but if the module FK is deleted or corrupted, this could raise an AttributeError.Add defensive programming:
def __str__(self) -> str: """Return a human-readable representation of the task level. Returns: str: Module name with task level name. """ - return f"{self.module.name} - {self.name}" + module_name = getattr(self.module, 'name', 'Unknown Module') if self.module else 'No Module' + return f"{module_name} - {self.name}"backend/apps/mentorship/models/task.py (2)
53-60
: Inconsistent field behavior for assigned_at vs auto-timestamps.The
assigned_at
field usesauto_now_add=True
, which sets the timestamp only on creation. However, if a task is reassigned (assignee changes), this timestamp won't update, making it misleading. Consider the workflow implications.If reassignment is expected, consider updating the field when assignee changes:
def save(self, *args, **kwargs): """Override save to update assigned_at when assignee changes.""" if self.pk and self.assignee: old_task = Task.objects.get(pk=self.pk) if old_task.assignee != self.assignee: self.assigned_at = timezone.now() super().save(*args, **kwargs)Or rename the field to
created_at
if it should only track creation time.
68-74
: Handle None assignee gracefully in str method.The
__str__
method correctly handles the case whereassignee
is None, but it doesn't handle the case whereassignee.login
might be None or unavailable.Add defensive handling:
def __str__(self) -> str: """Return a human-readable representation of the task.""" + assignee_display = getattr(self.assignee, 'login', 'Unknown User') if self.assignee else None return ( - f"Task for '{self.issue.title}' assigned to {self.assignee.login}" + f"Task for '{self.issue.title}' assigned to {assignee_display}" if self.assignee else f"Task: {self.issue.title} (Unassigned)" )backend/apps/mentorship/migrations/0002_module_labels_task.py (1)
62-71
: Inconsistent help_text between migrations.In this migration, the
assignee
field has help_text "The GitHub user assigned to this task." but in migration 0003 and the model definition, it's "The mentee assigned to this task." This inconsistency could cause confusion.The help_text should be consistent across migrations. Consider updating the model definition to match the intended purpose (mentee vs GitHub user).
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
backend/apps/mentorship/admin.py
(2 hunks)backend/apps/mentorship/migrations/0002_module_labels_task.py
(1 hunks)backend/apps/mentorship/migrations/0003_alter_task_assignee_tasklevel_task_level.py
(1 hunks)backend/apps/mentorship/models/__init__.py
(1 hunks)backend/apps/mentorship/models/common/__init__.py
(1 hunks)backend/apps/mentorship/models/common/status.py
(1 hunks)backend/apps/mentorship/models/module.py
(2 hunks)backend/apps/mentorship/models/task.py
(1 hunks)backend/apps/mentorship/models/tasl_level.py
(1 hunks)
🧠 Learnings (1)
backend/apps/mentorship/models/common/status.py (1)
Learnt from: Rajgupta36
PR: #1717
File: frontend/src/components/ModuleForm.tsx:112-134
Timestamp: 2025-07-14T16:18:07.287Z
Learning: In the OWASP Nest mentorship system, date validation for modules (ensuring start date precedes end date) is handled on the backend in the module GraphQL mutations via the _validate_module_dates
helper function in backend/apps/mentorship/graphql/mutations/module.py, which prevents invalid date ranges from being stored in the database.
🪛 GitHub Actions: Run CI/CD
backend/apps/mentorship/models/__init__.py
[error] 9-9: CSpell: Unknown word 'tasl' detected.
backend/apps/mentorship/admin.py
[error] 11-11: CSpell: Unknown word 'tasl' detected.
🧰 Additional context used
🧠 Learnings (1)
backend/apps/mentorship/models/common/status.py (1)
Learnt from: Rajgupta36
PR: #1717
File: frontend/src/components/ModuleForm.tsx:112-134
Timestamp: 2025-07-14T16:18:07.287Z
Learning: In the OWASP Nest mentorship system, date validation for modules (ensuring start date precedes end date) is handled on the backend in the module GraphQL mutations via the _validate_module_dates
helper function in backend/apps/mentorship/graphql/mutations/module.py, which prevents invalid date ranges from being stored in the database.
🪛 GitHub Actions: Run CI/CD
backend/apps/mentorship/models/__init__.py
[error] 9-9: CSpell: Unknown word 'tasl' detected.
backend/apps/mentorship/admin.py
[error] 11-11: CSpell: Unknown word 'tasl' detected.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (10)
backend/apps/mentorship/models/__init__.py (1)
8-8
: LGTM: Task model import looks correct.The Task model import follows proper Django conventions and aligns with the PR objectives.
backend/apps/mentorship/models/common/__init__.py (1)
4-4
: LGTM: Status model import is properly added.The Status import correctly exposes the new abstract Status model for use by other models in the mentorship app.
backend/apps/mentorship/models/module.py (2)
8-12
: LGTM: Import formatting improvement.The multi-line import style improves readability and follows Python best practices for long import statements.
49-53
: LGTM: Labels field implementation is correct.The JSONField configuration is appropriate with:
blank=True
allowing empty values in formsdefault=list
providing a safe mutable default- Proper verbose name for admin interface
backend/apps/mentorship/admin.py (2)
91-110
: LGTM: TaskAdmin configuration is comprehensive.The admin class provides excellent functionality with:
- Comprehensive list display showing key task information
- Good search fields covering issue title, assignee, and module
- Useful filters for status, module, and assignee
133-134
: LGTM: Admin registrations are correct.Both new admin classes are properly registered with the Django admin site.
backend/apps/mentorship/models/common/status.py (1)
6-25
: LGTM: Status model implementation is well-designed.The abstract Status model provides:
- Clear StatusChoices with appropriate values and labels
- Proper CharField configuration with sensible max_length
- Good default value (TODO)
- Abstract base class design for reusability
backend/apps/mentorship/models/tasl_level.py (1)
42-48
: Verify the self-referential relationship configuration.The
needs
field creates a self-referential many-to-many relationship for prerequisites. The configuration looks correct withsymmetrical=False
and appropriate related names, which properly supports dependency chains.backend/apps/mentorship/migrations/0003_alter_task_assignee_tasklevel_task_level.py (1)
69-80
: Verify the field addition order and dependencies.The
level
field is added to thetask
model after creating theTaskLevel
model, which is the correct order to avoid foreign key reference errors. The field definition matches the model specification.backend/apps/mentorship/migrations/0002_module_labels_task.py (1)
31-43
: Status choices verified
The hardcoded choices in0002_module_labels_task.py
align exactly withStatusChoices
inbackend/apps/mentorship/models/common/status.py
. No further action required.
backend/apps/mentorship/migrations/0003_alter_task_assignee_tasklevel_task_level.py
Show resolved
Hide resolved
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.
Actionable comments posted: 1
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
backend/apps/mentorship/admin.py
(2 hunks)backend/apps/mentorship/models/__init__.py
(1 hunks)backend/apps/mentorship/models/task_level.py
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- backend/apps/mentorship/models/init.py
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/apps/mentorship/admin.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Run frontend e2e tests
🔇 Additional comments (5)
backend/apps/mentorship/models/task_level.py (5)
1-6
: LGTM! Clean imports and documentation.The file header follows Python best practices with proper docstring and minimal necessary imports.
8-15
: Well-structured model declaration.The class declaration and Meta configuration follow Django best practices with appropriate table naming, ordering, and documentation.
34-48
: Well-designed relationship fields.The foreign key and many-to-many relationships are properly configured with appropriate delete behavior and related names. The self-referential prerequisite relationship with
symmetrical=False
correctly models the directional nature of prerequisites.
50-57
: Excellent string representation method.The
__str__
method is well-documented and provides a clear, informative representation combining module and task level names.
22-26
: Fix mutable default argument in JSONField.Using
default=list
creates a mutable default that can lead to unexpected behavior where all instances share the same list object.Apply this fix:
- github_labels = models.JSONField( - default=list, - blank=True, - verbose_name="GitHub Labels", - ) + github_labels = models.JSONField( + default=list, + blank=True, + verbose_name="GitHub Labels", + )Wait, let me correct that - the proper fix is:
- github_labels = models.JSONField( - default=list, - blank=True, - verbose_name="GitHub Labels", - ) + github_labels = models.JSONField( + default=lambda: [], + blank=True, + verbose_name="GitHub Labels", + )Likely an incorrect or invalid review comment.
default="", | ||
) | ||
|
||
github_labels = models.JSONField( |
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.
Keep the naming consistent -- either github_labels
or labels
everywhere (see the Module
model)
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.
Actionable comments posted: 3
♻️ Duplicate comments (1)
backend/apps/mentorship/models/task.py (1)
16-16
: The unique_together constraint remains problematic for task reassignment workflows.This constraint was previously identified as too restrictive. It prevents reassigning tasks after completion or when assignees change, which is common in mentorship workflows.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
backend/apps/mentorship/admin.py
(2 hunks)backend/apps/mentorship/migrations/0002_module_labels_task.py
(1 hunks)backend/apps/mentorship/migrations/0003_tasklevel_task_level.py
(1 hunks)backend/apps/mentorship/models/task.py
(1 hunks)backend/apps/mentorship/models/task_level.py
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- backend/apps/mentorship/admin.py
- backend/apps/mentorship/migrations/0002_module_labels_task.py
- backend/apps/mentorship/models/task_level.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Run frontend e2e tests
- GitHub Check: Run frontend unit tests
- GitHub Check: Run backend tests
- GitHub Check: CodeQL (python)
- GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (3)
backend/apps/mentorship/models/task.py (2)
69-73
: Avoid mutable default arguments in model fields.Using
default=dict
creates a shared mutable object across all instances, which can lead to unexpected behavior where changes to one instance's metadata affect others.Apply this fix to use a callable default:
metadata = models.JSONField( - default=dict, + default=dict, blank=True, help_text="Optional data", )Wait, that's not the right fix. Use a lambda or callable:
metadata = models.JSONField( - default=dict, + default=lambda: {}, blank=True, help_text="Optional data", )Likely an incorrect or invalid review comment.
44-51
: TaskLevel model verifiedThe
TaskLevel
model is defined inbackend/apps/mentorship/models/task_level.py
with appropriate fields, metadata (db_table, ordering), and relationships (module FK and self-referential M2M for prerequisites). It aligns correctly with thelevel = ForeignKey("mentorship.TaskLevel", ...)
usage in theTask
model. No further changes required.backend/apps/mentorship/migrations/0003_tasklevel_task_level.py (1)
53-64
: The level field addition looks correct.The migration properly adds the nullable foreign key relationship between Task and TaskLevel with appropriate cascade behavior (SET_NULL).
) | ||
|
||
name = models.CharField( | ||
max_length=200, |
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.
default=""
?
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.
Actionable comments posted: 2
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
backend/apps/mentorship/admin/__init__.py
(1 hunks)backend/apps/mentorship/admin/task_level.py
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- backend/apps/mentorship/admin/init.py
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: backend/apps/mentorship/graphql/mutations/module.py:28-29
Timestamp: 2025-07-16T13:49:58.648Z
Learning: In the OWASP Nest mentorship system, mentors can be created with only github_user initially (without nest_user) when assigned to modules. This allows mentors to be assigned before they've signed into the system. When these users eventually sign in, the nest_user is automatically linked to the existing github_user, creating a complete mentor profile. This design provides flexibility in mentor assignment workflows.
🪛 GitHub Actions: Run CI/CD
backend/apps/mentorship/admin/task_level.py
[error] 1-7: pre-commit hook 'ruff' failed due to formatting issues. The hook made changes to this file to fix errors. Run 'pre-commit run --all-files' locally to reproduce and fix.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: CodeQL (javascript-typescript)
- GitHub Check: CodeQL (python)
🔇 Additional comments (2)
backend/apps/mentorship/admin/task_level.py (2)
3-4
: LGTM!The imports are correct and appropriate for Django admin configuration.
7-20
: Admin configuration looks good.The TaskLevelAdmin class provides a sensible configuration with appropriate fields for display and search functionality. The list_display includes key fields like description, labels, module, and name, while search_fields enables searching by name and related module name.
|
* Added Task module * Update code * Update code * Added TaskLevel Model * spell fix * update code * update code * updated schema * update code * update code --------- Co-authored-by: Arkadii Yakovets <[email protected]>
Proposed change
Resolves #1760
description
Created the TaskLevel model according to the issue
Checklist