Skip to content

Implement GraphQL queries for contributor recognition certificate pages#4962

Open
anurag2787 wants to merge 16 commits into
OWASP:feature/contributor-recognition-programfrom
anurag2787:crp-graphql
Open

Implement GraphQL queries for contributor recognition certificate pages#4962
anurag2787 wants to merge 16 commits into
OWASP:feature/contributor-recognition-programfrom
anurag2787:crp-graphql

Conversation

@anurag2787

@anurag2787 anurag2787 commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Proposed change

This PR implements GraphQL queries and nodes required for the Contributor Recognition certificate pages.

Resolves #4949

Checklist

  • Required: I followed the contributing workflow
  • Required: I verified that my code works as intended and resolves the issue as described
  • Required: I ran make check-test locally: all warnings addressed, tests passed
  • I used AI for code, documentation, tests, or communication related to this PR

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e6e1854d-5c15-4d59-b73c-19addc92c2e1

📥 Commits

Reviewing files that changed from the base of the PR and between df9189c and b65ed29.

📒 Files selected for processing (2)
  • backend/apps/owasp/Makefile
  • cspell/custom-dict.txt

Summary by CodeRabbit

Release Notes

  • New Features
    • Added certificate system for contributors to view earned certificates reflecting contribution recognition.
    • Implemented automatic contribution scoring based on merged pull requests, opened pull requests, and completed issues.
    • Contributors assigned tiers based on calculated contribution scores.
    • Added score recalculation capability for administrators.

Walkthrough

Adds a Contributor Recognition Program (CRP) subsystem: renames four CRP model DB tables to owasp_crp_* with a migration, introduces a ContributionScoreCalculator service, a CertificateService with pluggable provider abstraction, new CertificateNode/ContributionScoreNode GraphQL types, CertificateQuery resolvers, UserNode extensions for score and certificate, an admin recalculate action, and a management command.

Changes

CRP Certificate & Score System

Layer / File(s) Summary
CRP model DB table renames and re-exports
backend/apps/owasp/models/crp/certificate.py, backend/apps/owasp/models/crp/contribution_score.py, backend/apps/owasp/models/crp/leaderboard_snapshot.py, backend/apps/owasp/models/crp/scoring_weight.py, backend/apps/owasp/models/__init__.py, backend/apps/owasp/migrations/0074_alter_certificate_table_and_more.py, backend/apps/owasp/admin/certificate.py, backend/apps/owasp/admin/leaderboard_snapshot.py, backend/apps/owasp/admin/scoring_weight.py
Four CRP model db_table values renamed to owasp_crp_*, enum imports redirected to crp.recognition_enums, migration added, models/__init__.py re-exports and admin imports updated accordingly.
Domain exception and StateReason enum
backend/apps/owasp/exceptions.py, backend/apps/github/models/generic_issue_model.py
CertificateIssuanceError exception added; GenericIssueModel.StateReason.COMPLETED TextChoices added for use in issue count queries.
Certificate issuance service and provider abstraction
backend/apps/owasp/services/__init__.py, backend/apps/owasp/services/certificate_providers.py, backend/apps/owasp/services/certificate_service.py
BaseCertificateProvider ABC, LocalCertificateProvider (writes Certificate via ORM), CertificateProviderFactory (resolves from settings.CERTIFICATE_PROVIDER), and CertificateService.issue_certificate (atomic, row-locked, idempotent, wraps errors as CertificateIssuanceError).
ContributionScoreCalculator
backend/apps/owasp/score_calculator.py
Loads ScoringWeight values, counts merged/opened PRs and completed issues per user with date filtering, computes weighted totals, maps to TierChoices thresholds, and provides recalculate_all() (batch with BulkSaveModel.bulk_save and certificate issuance) and recalculate_user() (single-user upsert).
GraphQL nodes: CertificateNode, ContributionScoreNode, UserNode extensions
backend/apps/owasp/api/internal/nodes/contribution_score.py, backend/apps/owasp/api/internal/nodes/certificate.py, backend/apps/github/api/internal/nodes/user.py
ContributionScoreNode exposes value; CertificateNode exposes id, issued_at, score, tier, is_verified, github_user; UserNode gains contribution_score and current_certificate resolvers with ORM prefetch/select optimizations.
CertificateQuery and OwaspQuery wiring
backend/apps/owasp/api/internal/queries/certificate.py, backend/apps/owasp/api/internal/queries/__init__.py
CertificateQuery adds certificate(id) (UUID lookup) and my_certificate (authenticated user's latest active certificate); registered in OwaspQuery.
Admin action, management command, and Makefile
backend/apps/owasp/admin/contribution_score.py, backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py, backend/apps/owasp/Makefile, cspell/custom-dict.txt
ContributionScoreAdmin gains a recalculate bulk action; management command owasp_crp_recognition_recalculate_scores runs recalculate_all() and raises CommandError on failures; Makefile target added; crp added to spell-check dictionary.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • OWASP/Nest#4974: Extends OWASP Certificate and ContributionScore Django admin classes with overlapping model import paths and admin configuration changes.

Suggested reviewers

  • arkid15r
  • kasya
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main change: implementing GraphQL queries for contributor recognition certificate pages, which matches the primary objective across all modified files.
Description check ✅ Passed The PR description is directly related to the changeset, explaining the implementation of GraphQL queries and nodes for contributor recognition certificates, referencing the linked issue #4949.
Linked Issues check ✅ Passed The PR fully implements the objectives from issue #4949: it creates GraphQL query infrastructure (CertificateQuery with certificate and my_certificate resolvers, CertificateNode), exposes certificate data through nodes and resolvers, and supports the frontend certificate display functionality.
Out of Scope Changes check ✅ Passed All changes are within scope for implementing certificate GraphQL queries: core infrastructure (models reorganization into CRP module, score calculator, certificate services), GraphQL nodes and queries, admin actions for recalculation, and supporting utilities like the management command.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/apps/github/models/generic_issue_model.py`:
- Around line 26-29: The StateReason enum class is incomplete and only includes
the COMPLETED choice. Add the additional state_reason values supported by
GitHub's API: NOT_PLANNED with value "not_planned", REOPENED with value
"reopened", and DUPLICATE with value "duplicate" to the StateReason enum in the
same format as the existing COMPLETED entry. This will ensure consistency with
the GitHub API and enable better IDE autocompletion when filtering by
state_reason fields in the future.

In `@backend/apps/owasp/admin/contribution_score.py`:
- Around line 46-69: The recalculate method processes potentially many users
without providing intermediate progress feedback, which could cause admins to
think the operation is stuck. Add periodic progress messages inside the loop in
the recalculate method by calling self.message_user with messages.INFO level at
regular intervals (e.g., every 100 processed users). You will need to import
messages from django.contrib at the top of the file to enable this.

In `@backend/apps/owasp/api/internal/queries/certificate.py`:
- Line 18: The parameter name `id` in the certificate method shadows Python's
builtin id() function. Rename the parameter from `id` to `certificate_id` (or
`pk` if preferred) and update all references to this parameter throughout the
method body to use the new name. Also check if this method is called elsewhere
in the codebase and update the argument names at those call sites to match the
renamed parameter.

In `@backend/apps/owasp/score_calculator.py`:
- Around line 358-392: The recalculate_user method does not handle exceptions
from CertificateService.issue_certificate(), allowing them to propagate and
abort the operation, while recalculate_all() catches and tracks these failures.
Either wrap the CertificateService.issue_certificate(user, total_score, tier)
call in a try/except block to match the error handling pattern used in
recalculate_all() by capturing the exception and logging it without aborting the
score update, or add clear documentation explaining the intentional difference
in error handling behavior between single-user and batch recalculation
operations.
- Around line 227-233: In the User query filter chain in the
`score_calculator.py` file, replace the `prefetch_related("contribution_score")`
call with `select_related("contribution_score")`. Since `contribution_score` is
a OneToOneField relation, using select_related will perform a JOIN in a single
query, which is more efficient than prefetch_related's separate query approach.
- Around line 163-182: The method `count_opened_issues` contains a filter for
`state_reason=Issue.StateReason.COMPLETED` which means it actually counts
completed issues, not opened issues, making the method name misleading. Rename
the method from `count_opened_issues` to `count_completed_issues` to accurately
reflect its behavior. Then locate and update all callers of this method
(including the call in `get_contribution_breakdown`) to use the new method name.

In `@backend/apps/owasp/services/certificate_providers.py`:
- Around line 44-48: The issue() method in the certificate_providers.py file
creates a Certificate instance via Certificate.objects.create() but does not
return it. Capture the return value from the Certificate.objects.create() call
and return it from the issue() method so callers can access certificate metadata
like the generated ID. Additionally, update the abstract base class signature to
reflect that the issue() method now returns a Certificate instance instead of
None.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bee30a1f-bc1a-463b-890a-3dc75a8af70b

📥 Commits

Reviewing files that changed from the base of the PR and between 5bae1cc and 2a9038c.

📒 Files selected for processing (26)
  • backend/apps/github/api/internal/nodes/user.py
  • backend/apps/github/models/generic_issue_model.py
  • backend/apps/owasp/Makefile
  • backend/apps/owasp/admin/certificate.py
  • backend/apps/owasp/admin/contribution_score.py
  • backend/apps/owasp/admin/leaderboard_snapshot.py
  • backend/apps/owasp/admin/scoring_weight.py
  • backend/apps/owasp/api/internal/nodes/certificate.py
  • backend/apps/owasp/api/internal/nodes/contribution_score.py
  • backend/apps/owasp/api/internal/queries/__init__.py
  • backend/apps/owasp/api/internal/queries/certificate.py
  • backend/apps/owasp/exceptions.py
  • backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py
  • backend/apps/owasp/migrations/0074_alter_certificate_table_and_more.py
  • backend/apps/owasp/models/__init__.py
  • backend/apps/owasp/models/crp/__init__.py
  • backend/apps/owasp/models/crp/certificate.py
  • backend/apps/owasp/models/crp/contribution_score.py
  • backend/apps/owasp/models/crp/leaderboard_snapshot.py
  • backend/apps/owasp/models/crp/recognition_enums.py
  • backend/apps/owasp/models/crp/scoring_weight.py
  • backend/apps/owasp/score_calculator.py
  • backend/apps/owasp/services/__init__.py
  • backend/apps/owasp/services/certificate_providers.py
  • backend/apps/owasp/services/certificate_service.py
  • cspell/custom-dict.txt

Comment thread backend/apps/github/models/generic_issue_model.py
Comment thread backend/apps/owasp/admin/contribution_score.py
Comment thread backend/apps/owasp/api/internal/queries/certificate.py Outdated
Comment thread backend/apps/owasp/score_calculator.py
Comment thread backend/apps/owasp/score_calculator.py
Comment thread backend/apps/owasp/score_calculator.py
Comment thread backend/apps/owasp/services/certificate_providers.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 26 files

Confidence score: 3/5

  • In backend/apps/owasp/score_calculator.py, the issue_opened path (including count_opened_issues) filters on state_reason=COMPLETED, which can undercount contributors with open issues and even skip them during recalculation; merging as-is risks incorrect contribution scores and recognition outcomes — fix the filter/logic to count genuinely opened issues before merging.
  • In backend/apps/owasp/api/internal/nodes/contribution_score.py, ContributionScoreNode omits the tier field, so clients (including certificate-related consumers) may receive incomplete contribution data and render outdated or missing tier info — add tier to the node/model mapping before merge.
  • In backend/apps/owasp/score_calculator.py, using prefetch_related for reverse OneToOne loading adds unnecessary query overhead during full recalculation, and backend/apps/owasp/management/commands/owasp_crp_recognition_recalculate_scores.py logs a broader scope than actually processed; this is lower risk but can hurt operability and debugging — switch to select_related and correct the command status message as a cleanup.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread backend/apps/owasp/score_calculator.py
Comment thread backend/apps/owasp/api/internal/nodes/contribution_score.py
Comment thread backend/apps/owasp/score_calculator.py
Comment thread backend/apps/owasp/score_calculator.py
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 18, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Re-trigger cubic

@anurag2787 anurag2787 marked this pull request as ready for review June 18, 2026 11:39
@anurag2787

Copy link
Copy Markdown
Collaborator Author

Hi @arkid15r pr is ready for review, the ci cd failure will be fixed after the sync to main branch #4974

@sonarqubecloud

Copy link
Copy Markdown

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 41.82510% with 153 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.88%. Comparing base (9efca86) to head (b65ed29).
⚠️ Report is 2 commits behind head on feature/contributor-recognition-program.

Files with missing lines Patch % Lines
backend/apps/owasp/score_calculator.py 22.60% 89 Missing ⚠️
...mmands/owasp_crp_recognition_recalculate_scores.py 0.00% 17 Missing ⚠️
backend/apps/owasp/services/certificate_service.py 46.42% 15 Missing ⚠️
backend/apps/owasp/admin/contribution_score.py 38.88% 11 Missing ⚠️
...end/apps/owasp/api/internal/queries/certificate.py 61.90% 8 Missing ⚠️
...ckend/apps/owasp/services/certificate_providers.py 66.66% 7 Missing ⚠️
backend/apps/github/api/internal/nodes/user.py 72.72% 3 Missing ⚠️
...ckend/apps/owasp/api/internal/nodes/certificate.py 78.57% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                             Coverage Diff                             @@
##           feature/contributor-recognition-program    #4962      +/-   ##
===========================================================================
- Coverage                                    98.74%   97.88%   -0.86%     
===========================================================================
  Files                                          547      554       +7     
  Lines                                        17185    17436     +251     
  Branches                                      2417     2435      +18     
===========================================================================
+ Hits                                         16969    17067      +98     
- Misses                                         127      280     +153     
  Partials                                        89       89              
Flag Coverage Δ
backend 98.25% <41.82%> (-1.17%) ⬇️
frontend 96.80% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
backend/apps/github/models/generic_issue_model.py 100.00% <100.00%> (ø)
backend/apps/owasp/admin/certificate.py 100.00% <100.00%> (ø)
backend/apps/owasp/admin/leaderboard_snapshot.py 100.00% <100.00%> (ø)
backend/apps/owasp/admin/scoring_weight.py 100.00% <100.00%> (ø)
...pps/owasp/api/internal/nodes/contribution_score.py 100.00% <100.00%> (ø)
backend/apps/owasp/exceptions.py 100.00% <100.00%> (ø)
backend/apps/owasp/models/crp/certificate.py 90.90% <100.00%> (ø)
...ackend/apps/owasp/models/crp/contribution_score.py 93.33% <100.00%> (ø)
...kend/apps/owasp/models/crp/leaderboard_snapshot.py 96.00% <100.00%> (ø)
backend/apps/owasp/models/crp/recognition_enums.py 100.00% <ø> (ø)
... and 9 more

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 15609d9...b65ed29. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@arkid15r arkid15r left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you resolve the conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants