- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 259
 
Added management command for linking issue #2000
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
          
     Open
      
      
            Rajgupta36
  wants to merge
  18
  commits into
  OWASP:feature/mentorship-portal
  
    
      
        
          
  
    
      Choose a base branch
      
     
    
      
        
      
      
        
          
          
        
        
          
            
              
              
              
  
           
        
        
          
            
              
              
           
        
       
     
  
        
          
            
          
            
          
        
       
    
      
from
Rajgupta36:command/filter-sync-issue
  
      
      
   
  
    
  
  
  
 
  
      
    base: feature/mentorship-portal
Could not load branches
            
              
  
    Branch not found: {{ refName }}
  
            
                
      Loading
              
            Could not load tags
            
            
              Nothing to show
            
              
  
            
                
      Loading
              
            Are you sure you want to change the base?
            Some commits from the old base branch may be removed from the timeline,
            and old review comments may become outdated.
          
          
  
     Open
                    Changes from 16 commits
      Commits
    
    
            Show all changes
          
          
            18 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      76cadcd
              
                Update docker-compose/local.yaml
              
              
                arkid15r bca0af1
              
                added adition fields and job for issue filter by labels
              
              
                Rajgupta36 c5cc58a
              
                updated code
              
              
                Rajgupta36 a00ed23
              
                pre commit
              
              
                Rajgupta36 3e13223
              
                added the makefile
              
              
                Rajgupta36 aaf19e0
              
                update suggestions
              
              
                Rajgupta36 830e1e3
              
                update code
              
              
                Rajgupta36 74ac095
              
                update suggestoin
              
              
                Rajgupta36 f95ed78
              
                added new task creation logic
              
              
                Rajgupta36 26573dd
              
                updated code
              
              
                Rajgupta36 c903c64
              
                added commands for sync issue labels
              
              
                Rajgupta36 4ed386d
              
                update code
              
              
                Rajgupta36 c3d77a2
              
                fix bug
              
              
                Rajgupta36 1c2d637
              
                enhanced the logic
              
              
                Rajgupta36 8172a00
              
                update suggestions
              
              
                Rajgupta36 f305d41
              
                update naming and fns
              
              
                Rajgupta36 2ef45f2
              
                upgraded migration
              
              
                Rajgupta36 00ff045
              
                update suggestion
              
              
                Rajgupta36 File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Generated by Django 5.2.4 on 2025-09-13 18:48 | ||
| 
     | 
||
| 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"), | ||
| ("mentorship", "0004_module_key_program_key_and_more"), | ||
| ] | ||
| 
     | 
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name="issue", | ||
| name="level", | ||
| field=models.ForeignKey( | ||
| blank=True, | ||
| help_text="The difficulty level of this issue.", | ||
| null=True, | ||
| on_delete=django.db.models.deletion.SET_NULL, | ||
| related_name="tasks", | ||
| to="mentorship.tasklevel", | ||
| ), | ||
| ), | ||
| ] | ||
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| mentorship-sync-module-issues: | ||
| @CMD="python manage.py sync_module_issues" $(MAKE) exec-backend-command | ||
| 
     | 
||
| mentorship-sync-issue-levels: | ||
| @CMD="python manage.py sync_issue_levels" $(MAKE) exec-backend-command | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              Empty file.
          
    
              Empty file.
          
    
        
          
  
    
      
          
            97 changes: 97 additions & 0 deletions
          
          97 
        
  backend/apps/mentorship/management/commands/sync_issue_levels.py
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| """A command to sync issue level with Tasklevel.""" | ||
| 
     | 
||
| from django.core.management.base import BaseCommand | ||
| from django.db.models import Prefetch | ||
| 
     | 
||
| from apps.github.models.issue import Issue | ||
| from apps.github.models.label import Label | ||
| from apps.mentorship.models.task_level import TaskLevel | ||
| from apps.mentorship.utils import normalize_name | ||
| 
     | 
||
| 
     | 
||
| class Command(BaseCommand): | ||
| """Syncs the `level` field on Issues based on matching labels, respecting Module constraints. | ||
| 
     | 
||
| If any label matches a TaskLevel in the Issue's Module, that TaskLevel is assigned. | ||
| """ | ||
| 
     | 
||
| help = "Assigns a TaskLevel to each Issue by matching labels within the same Module." | ||
| 
     | 
||
| def _build_module_level_maps(self, all_levels): | ||
| """Build a mapping from module ID to a dictionary of data. | ||
| 
     | 
||
| The dictionary contains a 'label_to_level_map' for normalized label/level | ||
| names to TaskLevel objects. | ||
| """ | ||
| module_data_map = {} | ||
| for level in all_levels: | ||
| module_id = level.module_id | ||
| level_map_container = module_data_map.setdefault(module_id, {"label_to_level_map": {}}) | ||
| level_map = level_map_container["label_to_level_map"] | ||
| 
     | 
||
| normalized_level_name = normalize_name(level.name) | ||
| level_map[normalized_level_name] = level | ||
| 
     | 
||
| for label_name in level.labels: | ||
| normalized_label = normalize_name(label_name) | ||
| level_map[normalized_label] = level | ||
| return module_data_map | ||
| 
     | 
||
| def _find_best_match_level( | ||
| self, | ||
| issue_labels_normalized, | ||
| issue_mentorship_modules, | ||
| module_data_map, | ||
| ): | ||
| """Find the best matching TaskLevel for an issue based on its labels and modules.""" | ||
| for module in issue_mentorship_modules: | ||
| if module.id in module_data_map: | ||
| module_level_map = module_data_map[module.id]["label_to_level_map"] | ||
| for label_name in issue_labels_normalized: | ||
| if label_name in module_level_map: | ||
| return module_level_map[label_name] | ||
| return None | ||
| 
     | 
||
| def handle(self, *args, **options): | ||
| self.stdout.write("Starting...") | ||
| 
     | 
||
| # 1. Build a per-module map (normalized label → TaskLevel) | ||
| all_levels = TaskLevel.objects.select_related("module").order_by("name") | ||
| 
     | 
||
| if not all_levels.exists(): | ||
| self.stdout.write( | ||
| self.style.WARNING("No TaskLevel objects found in the database. Exiting.") | ||
| ) | ||
| return | ||
| 
     | 
||
| module_data_map = self._build_module_level_maps(all_levels) | ||
| self.stdout.write(f"Built label maps for {len(module_data_map)} modules.") | ||
| 
     | 
||
| # 2.match issue labels to TaskLevels | ||
| issues_to_update = [] | ||
| issues_query = Issue.objects.prefetch_related( | ||
| Prefetch("labels", queryset=Label.objects.only("name")), | ||
| "mentorship_modules", | ||
| ).select_related("level") | ||
| 
     | 
||
| for issue in issues_query: | ||
| issue_labels_normalized = {normalize_name(label.name) for label in issue.labels.all()} | ||
| 
     | 
||
| best_match_level = self._find_best_match_level( | ||
| issue_labels_normalized, | ||
| list(issue.mentorship_modules.all()), | ||
| module_data_map, | ||
| ) | ||
| 
     | 
||
| if issue.level != best_match_level: | ||
| issue.level = best_match_level | ||
| issues_to_update.append(issue) | ||
| 
     | 
||
| if issues_to_update: | ||
| updated_count = len(issues_to_update) | ||
| Issue.objects.bulk_update(issues_to_update, ["level"]) | ||
| self.stdout.write( | ||
| self.style.SUCCESS(f"Successfully updated the level for {updated_count} issues.") | ||
| ) | ||
| else: | ||
| self.stdout.write(self.style.SUCCESS("All issue levels are already up-to-date.")) | 
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.