-
-
Couldn't load subscription status.
- Fork 246
Feature/daily badge sync job 1763 #2047
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
Merged
arkid15r
merged 69 commits into
OWASP:main
from
Dhirajsharma2060:feature/daily-badge-sync-job-1763
Aug 28, 2025
Merged
Changes from 24 commits
Commits
Show all changes
69 commits
Select commit
Hold shift + click to select a range
4d339f7
test: add unit tests for SortBy component
Dhirajsharma2060 873742c
test: update SortBy component tests for prop naming and accessibility
Dhirajsharma2060 ab51c73
test: import React in SortBy component tests for consistency
Dhirajsharma2060 9b5197d
made some chnages
Dhirajsharma2060 a247251
test: update SortBy component tests for improved accessibility and cl…
Dhirajsharma2060 1da6630
Merge branch 'main' into feature/test-sortby-component-1915
Dhirajsharma2060 c1de740
test: ensure order toggle button functionality in SortBy component tests
Dhirajsharma2060 02fc6e9
feat: add has_full_name filter to top contributors query and model
Dhirajsharma2060 22f2cd2
fix: update regex for user name filtering in RepositoryContributor qu…
Dhirajsharma2060 c466bc4
Merge branch 'main' into pr/Dhirajsharma2060/1993
arkid15r ffb6447
Update code
arkid15r f216e86
test: enhance RepositoryContributor tests with full name filter valid…
Dhirajsharma2060 640dc29
Merge branch 'feature/top-contributors-has-full-name-filter-1990' of …
Dhirajsharma2060 8907d0b
refactor: use class constants for regex pattern and mock data in Repo…
Dhirajsharma2060 f514db2
test: fix regex filter call in has_full_name filter validation
Dhirajsharma2060 30ab091
Update code
arkid15r e4fae6e
Update tests
arkid15r f2fb122
Merge branch 'main' into feature/top-contributors-has-full-name-filte…
arkid15r 8e39dd6
Update code
arkid15r 854fdf4
Update tests
arkid15r 80fa7b5
Update test
arkid15r 6d953e4
feat: periodic job to sync OWASP Employee badges (#1762)
Dhirajsharma2060 e0835ed
Merge remote-tracking branch 'origin/feature/daily-badge-sync-job-176…
Dhirajsharma2060 fa5020f
fix: optimize badge assignment logic and improve test coverage for sy…
Dhirajsharma2060 713a7b5
refactor: clean up comments in sync_user_badges test cases for clarity
Dhirajsharma2060 17000eb
refactor: remove unused mock_badge fixture from sync_user_badges test
Dhirajsharma2060 193af74
feat: add management command to sync OWASP Staff badges and correspon…
Dhirajsharma2060 e56ccdb
refactor: optimize badge assignment logic for OWASP Staff badge sync
Dhirajsharma2060 bcef54a
Merge branch 'main' into pr/Dhirajsharma2060/2047
arkid15r 9fc6338
Update code
arkid15r 56c8901
feat: add badges field to User model and update badge sync logic for …
Dhirajsharma2060 8631d06
feat: add badges field to User model and update related tests for bad…
Dhirajsharma2060 3bc74e5
test: ensure no badge operations are performed when no employees are …
Dhirajsharma2060 91594ed
test: enhance user filter logic and improve badge assignment messages…
Dhirajsharma2060 8afe47e
test: refine user filter logic for badge assignment and enhance handl…
Dhirajsharma2060 e88656d
test: refactor user filter logic in badge assignment tests for improv…
Dhirajsharma2060 348c859
test: simplify user filter logic in badge assignment tests for improv…
Dhirajsharma2060 b0d3e84
test: simplify user filter logic by extracting helper functions for i…
Dhirajsharma2060 de0872b
test: update patch paths for badge and user objects in sync_user_badg…
Dhirajsharma2060 f0d7376
Merge branch 'main' into pr/Dhirajsharma2060/2047
arkid15r e9014b9
Update code
arkid15r 3849ea6
test: update patch paths for badge and user objects in TestSyncUserBa…
Dhirajsharma2060 bb4dd30
Fix #1912: Added test for SecondaryCard component (#2069)
rasesh-here d1e1871
test: add unit tests for GeneralCompliantComponent (#2018)
addresskrish cc6278c
Added Light Theme Support for Contribution HeatMap (#2072)
Abhay056 864e98b
feat: add comprehensive unit tests for DisplayIcon component (#2048)
RizWaaN3024 3c9b1d3
enhance:change-hover-color-action-button (#1978)
VijeshVS d468668
Test: add unit tests for BarChart component #1801 (#1904)
MohdWaqar98 73d4db7
Project Dasbored Drop Down Test case has been made (#2052)
SOHAMPAL23 a4ab5d0
fix: update command references in badge management tests
Dhirajsharma2060 91a2d67
Merge branch 'main' into pr/Dhirajsharma2060/2047
arkid15r 6131c06
Update code
arkid15r 6086707
Merge branch 'main' into feature/daily-badge-sync-job-1763
kasya 1a9c89b
fix: update badge management command to correctly filter users by bad…
Dhirajsharma2060 9fe34c5
style: format code for better readability in badge assignment logic
Dhirajsharma2060 7c7781f
fix: update badge assignment logic to use UserBadge model and remove …
Dhirajsharma2060 0e70c0e
Merge branch 'feature/daily-badge-sync-job-1763' of github.com:Dhiraj…
Dhirajsharma2060 4b2dafd
fix: include owasp Makefile in backend Makefile
Dhirajsharma2060 d2d6ca7
fix: improve badge removal logic for non-OWASP employees
Dhirajsharma2060 caf00f7
fix: add unique constraint for user and badge in UserBadge model
Dhirajsharma2060 49794b6
Update code
arkid15r 798ecfe
Revert volumes
arkid15r 10473bb
Merge branch 'main' into feature/daily-badge-sync-job-1763
arkid15r 4d29a6d
feat: add is_active field to UserBadge model and update badge assignm…
Dhirajsharma2060 5f139f9
style: format migration file for userbadge is_active field
Dhirajsharma2060 13791ae
test: mock return value for UserBadge get_or_create in badge sync tests
Dhirajsharma2060 4d95c48
fix: correct docstring for nest_update_badges management command tests
Dhirajsharma2060 8476044
Merge branch 'main' into pr/Dhirajsharma2060/2047
arkid15r d8b46a6
Update code
arkid15r 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
58 changes: 58 additions & 0 deletions
58
backend/apps/github/management/commands/github_sync_user_badges.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,58 @@ | ||
| """Management command to sync badges for users based on their roles/attributes.""" | ||
|
|
||
| import logging | ||
|
|
||
| from django.core.management.base import BaseCommand | ||
|
|
||
| from apps.github.models.user import User | ||
| from apps.owasp.models.badge import Badge | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class Command(BaseCommand): | ||
| """Sync badges for users based on their roles and attributes.""" | ||
|
|
||
| help = "Sync badges for users based on their roles and attributes" | ||
|
|
||
| def handle(self, *args, **options): | ||
| """Execute the command.""" | ||
| self.stdout.write("Syncing user badges...") | ||
| self.sync_owasp_employee_badge() | ||
| self.stdout.write(self.style.SUCCESS("User badges sync completed")) | ||
|
|
||
| def sync_owasp_employee_badge(self): | ||
| """Sync OWASP Employee badge for users.""" | ||
| # Get or create the OWASP Employee badge | ||
| badge, created = Badge.objects.get_or_create( | ||
| name="OWASP Employee", | ||
| defaults={ | ||
| "description": "Official OWASP Employee", | ||
| "css_class": "fa-user-shield", | ||
| "weight": 100, # High weight for importance | ||
| }, | ||
| ) | ||
|
|
||
| if created: | ||
| logger.info("Created 'OWASP Employee' badge") | ||
| self.stdout.write(f"Created badge: {badge.name}") | ||
|
|
||
| # Assign badge to employees who don't have it (avoiding N+1 queries) | ||
| employees_without_badge = User.objects.filter(is_owasp_employee=True).exclude(badges=badge) | ||
| count = employees_without_badge.count() | ||
|
|
||
| for user in employees_without_badge: | ||
| user.badges.add(badge) | ||
|
|
||
| logger.info("Added 'OWASP Employee' badge to %s users", count) | ||
| self.stdout.write(f"Added badge to {count} employees") | ||
|
|
||
| # Remove badge from non-OWASP employees | ||
| non_employees = User.objects.filter(is_owasp_employee=False, badges=badge) | ||
| removed_count = non_employees.count() | ||
|
|
||
| for user in non_employees: | ||
| user.badges.remove(badge) | ||
|
|
||
| logger.info("Removed 'OWASP Employee' badge from %s users", removed_count) | ||
| self.stdout.write(f"Removed badge from {removed_count} non-employees") |
152 changes: 152 additions & 0 deletions
152
backend/tests/apps/github/management/commands/github_sync_user_badges_test.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,152 @@ | ||
| """Tests for the sync_user_badges management command.""" | ||
|
|
||
| from io import StringIO | ||
| from unittest.mock import MagicMock, patch | ||
|
|
||
| import pytest | ||
| from django.core.management import call_command | ||
|
|
||
| OWASP_EMPLOYEE_BADGE_NAME = "OWASP Employee" | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def mock_badge(): | ||
| badge = MagicMock() | ||
| badge.name = OWASP_EMPLOYEE_BADGE_NAME | ||
| badge.css_class = "fa-user-shield" | ||
| badge.id = 1 | ||
| return badge | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| class TestSyncUserBadgesCommand: | ||
| """Test the sync_user_badges management command.""" | ||
|
|
||
| @patch("apps.owasp.models.badge.Badge.objects.get_or_create") | ||
| @patch("apps.github.models.user.User.objects.filter") | ||
| def test_sync_owasp_employee_badge(self, mock_user_filter, mock_badge_get_or_create): | ||
| # Set up badge mock | ||
| mock_badge = MagicMock() | ||
| mock_badge.name = OWASP_EMPLOYEE_BADGE_NAME | ||
| mock_badge.id = 1 | ||
| mock_badge_get_or_create.return_value = (mock_badge, False) | ||
|
|
||
| # Set up employee mocks - with exclude() method properly mocked | ||
| mock_employee = MagicMock() | ||
| mock_employees = MagicMock() | ||
| mock_employees_without_badge = MagicMock() | ||
| mock_employees_without_badge.__iter__.return_value = [mock_employee] | ||
| mock_employees_without_badge.count.return_value = 1 | ||
| mock_employees.exclude.return_value = mock_employees_without_badge | ||
|
|
||
| # Set up former employee mocks | ||
| mock_former_employee = MagicMock() | ||
| mock_former_employees = MagicMock() | ||
| mock_former_employees.__iter__.return_value = [mock_former_employee] | ||
| mock_former_employees.count.return_value = 1 | ||
|
|
||
| # Configure filter side effects | ||
| mock_user_filter.side_effect = [ | ||
| mock_employees, # is_owasp_employee=True | ||
| mock_former_employees, # is_owasp_employee=False, badges=badge | ||
| ] | ||
|
|
||
| # Call the command | ||
| out = StringIO() | ||
| call_command("github_sync_user_badges", stdout=out) | ||
|
|
||
| # Verify badge assignments | ||
| mock_employee.badges.add.assert_called_once_with(mock_badge) | ||
| mock_former_employee.badges.remove.assert_called_once_with(mock_badge) | ||
|
|
||
| # Check command output | ||
| output = out.getvalue() | ||
| assert "User badges sync completed" in output | ||
| assert "Added badge to 1 employees" in output | ||
| assert "Removed badge from 1 non-employees" in output | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| @patch("apps.owasp.models.badge.Badge.objects.get_or_create") | ||
| @patch("apps.github.models.user.User.objects.filter") | ||
| def test_badge_creation(self, mock_user_filter, mock_badge_get_or_create): | ||
| # Set up badge creation mock | ||
| mock_badge = MagicMock() | ||
| mock_badge.name = OWASP_EMPLOYEE_BADGE_NAME | ||
| mock_badge_get_or_create.return_value = (mock_badge, True) | ||
|
|
||
| # Set up empty querysets | ||
| mock_employees = MagicMock() | ||
| mock_employees.__iter__.return_value = [] | ||
| mock_employees.count.return_value = 0 | ||
| mock_former_employees = MagicMock() | ||
| mock_former_employees.__iter__.return_value = [] | ||
| mock_former_employees.count.return_value = 0 | ||
|
|
||
| mock_user_filter.side_effect = [mock_employees, mock_former_employees] | ||
|
|
||
| # Call the command | ||
| out = StringIO() | ||
| call_command("github_sync_user_badges", stdout=out) | ||
|
|
||
| # Verify badge creation and defaults | ||
|
|
||
| mock_badge_get_or_create.assert_called_once_with( | ||
| name="OWASP Employee", | ||
| defaults={ | ||
| "description": "Official OWASP Employee", | ||
| "css_class": "fa-user-shield", | ||
| "weight": 100, | ||
| }, | ||
| ) | ||
|
|
||
| # Check command output | ||
| output = out.getvalue() | ||
| assert f"Created badge: {mock_badge.name}" in output | ||
|
|
||
| @patch("apps.owasp.models.badge.Badge.objects.get_or_create") | ||
| @patch("apps.github.models.user.User.objects.filter") | ||
| def test_command_idempotency(self, mock_user_filter, mock_badge_get_or_create): | ||
| """Test that running the command multiple times has the same effect as running it once.""" | ||
| # Set up badge mock | ||
| mock_badge = MagicMock() | ||
| mock_badge.name = OWASP_EMPLOYEE_BADGE_NAME | ||
| mock_badge.id = 1 | ||
| mock_badge_get_or_create.return_value = (mock_badge, False) | ||
|
|
||
| # Set up employee mock that already has the badge | ||
| mock_employee_with_badge = MagicMock() | ||
| # This employee already has the badge | ||
| mock_employee_with_badge.badges.filter.return_value.exists.return_value = True | ||
| mock_employees = MagicMock() | ||
| mock_employees.__iter__.return_value = [mock_employee_with_badge] | ||
| # Using exclude() would return 0 employees without the badge | ||
| mock_employees.exclude.return_value = MagicMock() | ||
| mock_employees.exclude.return_value.count.return_value = 0 | ||
|
|
||
| # No former employees have the badge | ||
| mock_non_employees_filter = MagicMock() | ||
| mock_non_employees_filter.count.return_value = 0 | ||
| mock_non_employees_filter.__iter__.return_value = [] | ||
|
|
||
| # Configure filter side effects for two command runs | ||
| mock_user_filter.side_effect = [ | ||
| mock_employees, # is_owasp_employee=True (first run) | ||
| mock_non_employees_filter, # is_owasp_employee=False (first run) | ||
| mock_employees, # is_owasp_employee=True (second run) | ||
| mock_non_employees_filter, # is_owasp_employee=False (second run) | ||
| ] | ||
|
|
||
| # First run | ||
| out1 = StringIO() | ||
| call_command("github_sync_user_badges", stdout=out1) | ||
|
|
||
| # Second run | ||
| out2 = StringIO() | ||
| call_command("github_sync_user_badges", stdout=out2) | ||
|
|
||
| # Verify no add/remove operations were performed | ||
| mock_employee_with_badge.badges.add.assert_not_called() | ||
|
|
||
| # Check both outputs contain zero-count messages | ||
| assert "Added badge to 0 employees" in out1.getvalue() | ||
| assert "Removed badge from 0 non-employees" in out1.getvalue() | ||
| assert "Added badge to 0 employees" in out2.getvalue() | ||
| assert "Removed badge from 0 non-employees" in out2.getvalue() | ||
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.
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.
Define this in the command and import here instead.