From e9c3f6f728d10b63ecf11d2bf8caf533a0743f21 Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Sat, 21 Mar 2026 17:35:45 +0530 Subject: [PATCH 01/10] feat: add calculated_score field and basic scoring logic --- backend/apps/github/models/user.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/backend/apps/github/models/user.py b/backend/apps/github/models/user.py index e075cb9101..2582674c39 100644 --- a/backend/apps/github/models/user.py +++ b/backend/apps/github/models/user.py @@ -55,7 +55,13 @@ class Meta: ) contributions_count = models.PositiveIntegerField( - verbose_name="Contributions count", default=0 + verbose_name="Contributions count", + default=0 + ) + + calculated_score = models.FloatField( + default=0, + help_text="Computed score based on contribution signals" ) contribution_data = models.JSONField( @@ -85,6 +91,12 @@ def issues(self): """ return self.created_issues.all() + def calculate_score(self): + score = 0.0 + # Base contribution score + score += float( self.contributions_count or 0 ) + return score + @property def nest_url(self) -> str: """Get Nest URL for user.""" @@ -170,6 +182,7 @@ def from_github(self, gh_user) -> None: setattr(self, model_field, value) self.is_bot = gh_user.type == "Bot" + self.calculated_score = self.calculate_score() def get_absolute_url(self): """Get absolute URL for the user.""" From c72c27379ed8234ea6973428ed7fd8a129484a15 Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Sun, 22 Mar 2026 15:25:26 +0530 Subject: [PATCH 02/10] Refactor scoring into modular components --- backend/apps/github/models/user.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backend/apps/github/models/user.py b/backend/apps/github/models/user.py index 2582674c39..141043bc1a 100644 --- a/backend/apps/github/models/user.py +++ b/backend/apps/github/models/user.py @@ -27,6 +27,24 @@ class User(NodeModel, GenericUserModel, TimestampedModel, UserIndexMixin): """User model.""" + calculated_score = models.FloatField( default=0 ) + def calculate_score(self): + return ( + self._contribution_score() + + self._consistency_score() + + self._recency_score() + ) + def _contribution_score(self): + return (self.contributions_count or 0) * 1.0 + def _consistency_score(self): + base = self.contributions_count or 0 + if base > 50: + return 25 + elif base > 10: + return 10 + return 0 + def _recency_score(self): + return 5 if (self.contributions_count or 0) > 0 else 0 class Meta: """Model options.""" @@ -184,6 +202,7 @@ def from_github(self, gh_user) -> None: self.is_bot = gh_user.type == "Bot" self.calculated_score = self.calculate_score() + def get_absolute_url(self): """Get absolute URL for the user.""" return f"/members/{self.nest_key}" From ccb63a65c62b1ad91dce8d11190ec78874cd02cd Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Sun, 22 Mar 2026 15:51:46 +0530 Subject: [PATCH 03/10] fix: remove duplicate scoring definitions and clean implementation --- backend/apps/github/models/user.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/backend/apps/github/models/user.py b/backend/apps/github/models/user.py index 141043bc1a..517ad96270 100644 --- a/backend/apps/github/models/user.py +++ b/backend/apps/github/models/user.py @@ -28,12 +28,14 @@ class User(NodeModel, GenericUserModel, TimestampedModel, UserIndexMixin): """User model.""" calculated_score = models.FloatField( default=0 ) + def calculate_score(self): return ( self._contribution_score() + self._consistency_score() + self._recency_score() ) + def _contribution_score(self): return (self.contributions_count or 0) * 1.0 def _consistency_score(self): @@ -109,12 +111,6 @@ def issues(self): """ return self.created_issues.all() - def calculate_score(self): - score = 0.0 - # Base contribution score - score += float( self.contributions_count or 0 ) - return score - @property def nest_url(self) -> str: """Get Nest URL for user.""" From 5351332f60c2f4e2db6d93b78a79d56ffafee9c5 Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Sun, 22 Mar 2026 16:12:04 +0530 Subject: [PATCH 04/10] feat: add leadership scoring component --- backend/apps/github/models/user.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/apps/github/models/user.py b/backend/apps/github/models/user.py index 517ad96270..6549ee2f35 100644 --- a/backend/apps/github/models/user.py +++ b/backend/apps/github/models/user.py @@ -48,6 +48,13 @@ def _consistency_score(self): def _recency_score(self): return 5 if (self.contributions_count or 0) > 0 else 0 + def _leadership_score(self): + score = 0 + # Simple leadership signal + if self.is_owasp_staff: + score += 30 + return score + class Meta: """Model options.""" From d9724fc20cb81164bb5789125a3d91541961f0ce Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Wed, 15 Apr 2026 18:10:04 +0530 Subject: [PATCH 05/10] Add migration for calculated_score field --- .../migrations/0045_add_calculated_score.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 backend/apps/github/migrations/0045_add_calculated_score.py diff --git a/backend/apps/github/migrations/0045_add_calculated_score.py b/backend/apps/github/migrations/0045_add_calculated_score.py new file mode 100644 index 0000000000..80fe10c9ad --- /dev/null +++ b/backend/apps/github/migrations/0045_add_calculated_score.py @@ -0,0 +1,15 @@ +from django.db import migrations, models +class Migration(migrations.Migration): + dependencies = [ + ("github", "0044_user_indexes"), + ] + operations = [ + migrations.AddField( + model_name="user", + name="calculated_score", + field=models.FloatField( + default=0, + help_text="Computed score based on contribution signals", + ), + ), + ] \ No newline at end of file From 833c73d7c091933c3858507eb7c008972817008d Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Wed, 15 Apr 2026 18:38:25 +0530 Subject: [PATCH 06/10] Fix newline at end of migration file --- backend/apps/github/migrations/0045_add_calculated_score.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/apps/github/migrations/0045_add_calculated_score.py b/backend/apps/github/migrations/0045_add_calculated_score.py index 80fe10c9ad..d502a2ad37 100644 --- a/backend/apps/github/migrations/0045_add_calculated_score.py +++ b/backend/apps/github/migrations/0045_add_calculated_score.py @@ -12,4 +12,5 @@ class Migration(migrations.Migration): help_text="Computed score based on contribution signals", ), ), - ] \ No newline at end of file + ] + \ No newline at end of file From af8e724d68ff87d1ef50bf948a1c4b867be436e9 Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Wed, 15 Apr 2026 19:16:49 +0530 Subject: [PATCH 07/10] fix: add trailing newline --- backend/apps/github/migrations/0045_add_calculated_score.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/apps/github/migrations/0045_add_calculated_score.py b/backend/apps/github/migrations/0045_add_calculated_score.py index d502a2ad37..80fe10c9ad 100644 --- a/backend/apps/github/migrations/0045_add_calculated_score.py +++ b/backend/apps/github/migrations/0045_add_calculated_score.py @@ -12,5 +12,4 @@ class Migration(migrations.Migration): help_text="Computed score based on contribution signals", ), ), - ] - \ No newline at end of file + ] \ No newline at end of file From 25b26940d785a18d305338955af062164a3ae0f1 Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Wed, 15 Apr 2026 19:23:29 +0530 Subject: [PATCH 08/10] fix: recalculate calculated_score and improve formatting --- .../github/management/commands/github_update_users.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/backend/apps/github/management/commands/github_update_users.py b/backend/apps/github/management/commands/github_update_users.py index 7b81bcc930..459d98a6c1 100644 --- a/backend/apps/github/management/commands/github_update_users.py +++ b/backend/apps/github/management/commands/github_update_users.py @@ -1,10 +1,8 @@ """A command to update GitHub users.""" import logging - from django.core.management.base import BaseCommand from django.db.models import Q, Sum - from apps.common.models import BATCH_SIZE from apps.github.models.repository_contributor import RepositoryContributor from apps.github.models.user import User @@ -50,10 +48,11 @@ def handle(self, *args, **options): prefix = f"{idx + offset + 1} of {active_users_count - offset}" self.stdout.write(f"{prefix:<10} {user.title}\n") - user.contributions_count = user_contributions.get(user.id, 0) + user.contributions_count = user_contributions.get( user.id, 0 ) + user.calculated_score = user.calculate_score() users.append(user) - if not len(users) % BATCH_SIZE: - User.bulk_save(users, fields=("contributions_count",)) + if len( users ) % BATCH_SIZE == 0: + User.bulk_save( users, fields=("contributions_count","calculated_score") ) - User.bulk_save(users, fields=("contributions_count",)) + User.bulk_save(users, fields=("contributions_count","calculated_score")) From 4b2759cd9fc0d7399307de934e16f806ee162709 Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Wed, 15 Apr 2026 19:28:43 +0530 Subject: [PATCH 09/10] fix: final cleanup and formatting --- .../apps/github/management/commands/github_update_users.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/apps/github/management/commands/github_update_users.py b/backend/apps/github/management/commands/github_update_users.py index 459d98a6c1..1dbb4eb164 100644 --- a/backend/apps/github/management/commands/github_update_users.py +++ b/backend/apps/github/management/commands/github_update_users.py @@ -52,7 +52,7 @@ def handle(self, *args, **options): user.calculated_score = user.calculate_score() users.append(user) - if len( users ) % BATCH_SIZE == 0: - User.bulk_save( users, fields=("contributions_count","calculated_score") ) + if len( users ) % BATCH_SIZE == 0: + User.bulk_save( users, fields=("contributions_count", "calculated_score") ) - User.bulk_save(users, fields=("contributions_count","calculated_score")) + User.bulk_save( users, fields=("contributions_count", "calculated_score") ) From 96b476c1777888e70335bbc151df39bb944e39ec Mon Sep 17 00:00:00 2001 From: Tanishq Meshram Date: Sat, 18 Apr 2026 22:21:44 +0530 Subject: [PATCH 10/10] Fix stale calculated_score issue in management command --- .../management/commands/github_update_users.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/backend/apps/github/management/commands/github_update_users.py b/backend/apps/github/management/commands/github_update_users.py index 1dbb4eb164..bbac550774 100644 --- a/backend/apps/github/management/commands/github_update_users.py +++ b/backend/apps/github/management/commands/github_update_users.py @@ -44,15 +44,16 @@ def handle(self, *args, **options): .annotate(total_contributions=Sum("contributions_count")) } users = [] - for idx, user in enumerate(active_users[offset:]): + for idx, user in enumerate( active_users[offset:] ): prefix = f"{idx + offset + 1} of {active_users_count - offset}" - self.stdout.write(f"{prefix:<10} {user.title}\n") - + self.stdout.write( f"{prefix:<10} {user.title}\n" ) + # update contributions user.contributions_count = user_contributions.get( user.id, 0 ) + # RECALCULATE SCORE user.calculated_score = user.calculate_score() - users.append(user) - - if len( users ) % BATCH_SIZE == 0: - User.bulk_save( users, fields=("contributions_count", "calculated_score") ) + # add to list + users.append( user ) + if not len( users ) % BATCH_SIZE: + User.bulk_save( users, fields=("contributions_count", "calculated_score") ) User.bulk_save( users, fields=("contributions_count", "calculated_score") )