-
-
Notifications
You must be signed in to change notification settings - Fork 313
Add Bounty Payouts Feature #3990
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
Conversation
- Introduced BountyPayoutsView to manage and track GitHub issue bounty payments. - Added a new URL path for bounty payouts and created a corresponding template. - Updated GitHubIssue model to include an assignee field for tracking contributors. - Implemented methods for adding comments and labels to GitHub issues via the API. - Enhanced bounties_list.html to include a link to manage bounty payouts. - Created a migration to add the assignee field to the GitHubIssue model.
WalkthroughThis changeset introduces a bounty payouts feature. A new URL route maps to the Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant R as URL Router
participant V as BountyPayoutsView
participant DB as Database
participant API as GitHub API/Cache
U->>R: GET /bounties/payouts/
R->>V: Dispatch GET request
V->>DB: Query closed GitHub issues with bounty labels
V->>API: Fetch bounty issues (cached for 30 mins)
API-->>V: Return bounty issues
V->>U: Render bounty_payouts.html with issue data
sequenceDiagram
participant U as User
participant R as URL Router
participant V as BountyPayoutsView
participant DB as Database
participant API as GitHub API
U->>R: POST action (refresh/pay/delete)
R->>V: Dispatch POST request
V->>DB/API: Process action based on request type
DB/API-->>V: Return operation result
V->>U: Return updated view with feedback
Tip ⚡🧪 Multi-step agentic review comment chat (experimental)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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
🧹 Nitpick comments (9)
website/views/organization.py (2)
2685-2725: Consider caching and refining get_context_data.The context data retrieval and counting logic (such as
paid_countandunpaid_count) are appropriate. If you anticipate larger volumes of records, consider memoizing or selectively caching these aggregates. This approach might help performance if repeated queries for the same filters become frequent.
2764-2773: Ensure CSRF and authorization.Refreshing issues (via
action == "refresh_issues") is currently allowed if the request has valid CSRF tokens. Verify that only authorized users (e.g., staff) can spam refresh the GitHub API, to avoid rate limits or overhead. This can be enforced at the form or view level.website/templates/bounty_payouts.html (4)
21-88: Provide a fallback flow for non-staff users.The top toolbar provides a “Fetch New GitHub Issues” button, presumably for staff usage. If non-staff or non-logged-in users accidentally visit this page, you might want to hide or disable the button. Consider checking
request.user.is_staffwithin the template for a consistent UX.
211-260: Payment logic clarity.Lines 243-261 reflect paid/unpaid statuses gracefully. Ensure that your code keeps consistency between displayed states in the UI and the
issue.sponsors_tx_id/issue.bch_tx_idfields in the DB. The user might be confused if the UI says “Paid” but a transaction ID is incomplete.
261-360: Missing logging or feedback on copy error.The BCH address copying logic gracefully handles success but does not handle potential errors in the
catchblock (e.g., older browsers). Consider adding a fallback or user feedback ifnavigator.clipboardfails.
452-496: Consolidate copy logic functions.You have two separate copy flows: one for the inline button (
copyBchAddress) and a second insidedocument.addEventListener('DOMContentLoaded'). Consider consolidating them into a single function for maintainability, ensuring consistent styling on success.website/models.py (3)
1792-1825: Newadd_labelsmethod follows best practices but lacks docstring exampleThe method correctly handles label additions to GitHub issues via the API with appropriate error handling. However, consider adding an example in the docstring showing the expected format of the
labelsparameter (e.g.,['bug', 'enhancement']).Both the
add_commentandadd_labelsmethods follow a similar pattern, which is good for consistency and maintainability.def add_labels(self, labels): """ Adds labels to this GitHub issue via the GitHub API. Parameters: labels: List of label strings to add + Example: add_labels(['bug', 'enhancement']) Returns True if successful, False otherwise. """
1769-1790: Consider refactoring common API request codeBoth
add_commentandadd_labelsmethods share similar code for extracting URL components and setting up the API request. This could be extracted into a private helper method to reduce duplication.+ def _prepare_github_api_request(self, endpoint): + """ + Prepares a GitHub API request by extracting owner, repo, and issue number. + Returns the API URL and headers. + """ + # Extract owner and repo from the URL + parts = self.url.split("/") + owner = parts[3] + repo = parts[4] + issue_number = parts[6] + + # GitHub API endpoint + api_url = f"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}/{endpoint}" + + # Setup headers + from django.conf import settings + headers = {"Authorization": f"token {settings.GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json"} + + return api_url, headers def add_comment(self, comment_text): """ Adds a comment to this GitHub issue via the GitHub API. Returns True if successful, False otherwise. """ import logging import requests - from django.conf import settings - - # Extract owner and repo from the URL - # URL format: https://github.com/owner/repo/issues/number - parts = self.url.split("/") - owner = parts[3] - repo = parts[4] - issue_number = parts[6] - - # GitHub API endpoint for adding comments - api_url = f"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}/comments" - - headers = {"Authorization": f"token {settings.GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json"} + api_url, headers = self._prepare_github_api_request("comments") data = {"body": comment_text} try:
1771-1774: URL parsing could be more robustThe current URL parsing assumes a specific GitHub URL format. Consider using a more robust URL parsing approach to handle potential variations in URL formats.
- # Extract owner and repo from the URL - # URL format: https://github.com/owner/repo/issues/number - parts = self.url.split("/") - owner = parts[3] - repo = parts[4] - issue_number = parts[6] + # Extract owner, repo and issue number from GitHub URL + from urllib.parse import urlparse + + parsed_url = urlparse(self.url) + path_parts = parsed_url.path.strip('/').split('/') + + # Handle different GitHub URL formats + if len(path_parts) >= 4 and path_parts[2] == 'issues': + owner = path_parts[0] + repo = path_parts[1] + issue_number = path_parts[3] + else: + # Log error for unexpected URL format + logger = logging.getLogger(__name__) + logger.error(f"Unexpected GitHub URL format: {self.url}") + return False
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
blt/urls.py(2 hunks)website/migrations/0233_githubissue_assignee.py(1 hunks)website/models.py(2 hunks)website/templates/bounties_list.html(1 hunks)website/templates/bounty_payouts.html(1 hunks)website/views/organization.py(1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
blt/urls.py (1)
website/views/organization.py (1) (1)
BountyPayoutsView(2662-3053)
website/views/organization.py (1)
website/models.py (10) (10)
GitHubIssue(1637-1825)Repo(1453-1530)Contributor(1078-1090)UserProfile(687-874)save(74-77)save(219-231)save(1121-1148)save(1256-1259)save(1500-1522)save(2187-2190)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: Run Tests
- GitHub Check: docker-test
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Run Tests
🔇 Additional comments (16)
blt/urls.py (2)
192-192: Import looks goodThe BountyPayoutsView is properly imported from the website.views.organization module.
637-637: Well-structured URL pattern for the new bounty payouts featureThe URL pattern is correctly defined, using the appropriate path, connecting to the BountyPayoutsView, and using a descriptive name that can be referenced in templates.
website/migrations/0233_githubissue_assignee.py (1)
1-24: Well-structured migration for GitHubIssue assignee fieldThis migration properly adds an assignee field to the GitHubIssue model as a foreign key to the contributor model. The field configuration is appropriate:
- It's optional (blank=True, null=True)
- It uses SET_NULL for deleted contributors
- It provides a descriptive related_name for reverse lookups
The migration depends on the correct previous migration (0232_bannedapp).
website/templates/bounties_list.html (3)
4-18: Improved template block formattingThe reformatting of template blocks with proper indentation improves code readability while maintaining the same functionality.
22-42: Well-designed bounty payouts navigation bannerThe new banner section effectively guides users to the bounty payouts feature with:
- Clear visual hierarchy with icon, title, and description
- Consistent styling with the application's design system
- Proper link to the new route using the correct URL pattern name
This enhances the user experience by making the new feature discoverable.
43-43: Appropriate spacing adjustmentThe margin adjustment on the container ensures proper spacing between the new banner and the existing content.
website/views/organization.py (4)
2667-2684: Validate business logic in get_queryset.The
get_querysetmethod correctly filters closed GitHub issues with a dollar tag and then applies additional filtering for paid/unpaid states. Consider adding robust error handling or logging in case an unexpectedpayment_statusvalue is passed. This ensures future modifications don't unintentionally break logic.
2726-2763: Add fallback logic for label-based searches.The
github_issues_with_bountiesmethod uses GitHub’s search endpoint with a$5label. If the label changes or if multiple bounty labels are introduced, it might fail to fetch relevant issues. Consider making the label dynamic (e.g., from the request parameters) or having a fallback label.
2970-3032: Review transaction ID validation for pay_bounty.You are pattern-matching the transaction ID to either a
ch_prefix for Sponsors or a 64-char hex for BCH. This is a pragmatic approach. However, consider adding a fallback validation or a more descriptive user-facing message if the input is invalid, ensuring user mistakes are handled gracefully.Would you like a script that scans for all lines referencing
tx_idin the codebase to confirm no duplicate or unsafe usage?
3033-3054: Confirm superuser restriction for delete_issue.The
delete_issueaction is gated behind arequest.user.is_superusercheck. If you want staff users (non-superuser) to handle some tasks, clarify whether staff should have deletion rights or if only superusers can remove issues. This ensures consistent application of your security model.website/templates/bounty_payouts.html (3)
1-20: Refine meta tags for SEO.Your metadata blocks (title, description, keywords, OG tags) are clearly defined. Consider reviewing their length, relevance, and distinctiveness to improve SEO. Also ensure no PII or secure tokens inadvertently appear in these blocks.
89-164: Document the $5 assumption.Your table and references are clearly designed around a $5 bounty. If multiple bounty amounts are introduced in the future, this might become limiting. Document or highlight that the current logic is restricted to $5 issues so future maintainers can adapt it easily.
361-451: Pagination style is consistent.The pagination block is well-structured, with first/last page navigation. All parameters are re-injected with
payment_status={{ current_payment_status }}, ensuring consistent filtering across pages. This is good practice.website/models.py (3)
1677-1683: Newassigneefield looks good and complements the model structureThe addition of the
assigneefield to theGitHubIssuemodel is well-implemented with appropriate null/blank constraints and CASCADE behavior. This is a good addition that aligns with the bounty payouts feature by enabling tracking of who is assigned to work on an issue.
1758-1791: Newadd_commentmethod is well-structured with proper error handlingThis method is well-implemented with:
- Appropriate URL parsing to extract owner, repo, and issue number
- Robust error handling that logs errors without raising exceptions
- Clean return of boolean success/failure indicator
The implementation aligns well with the bounty payouts feature requirements.
1779-1780:Details
❓ Verification inconclusive
Verify GitHub token is properly configured
The code assumes
settings.GITHUB_TOKENis available. Ensure this setting is properly configured in the production environment, as missing or invalid tokens will prevent these features from working.Verify that the GITHUB_TOKEN is properly set by checking the settings file:
🏁 Script executed:
#!/bin/bash # Check if GITHUB_TOKEN is set in settings files grep -r "GITHUB_TOKEN" --include="*.py" .Length of output: 7039
Action Required: Validate GitHub Token Setup in Production
The code in
blt/settings.pyassignsGITHUB_TOKENfrom the environment with a fallback to"blank". While this definition is present and referenced throughout the codebase (e.g., inwebsite/models.pyand elsewhere), please ensure that in your production environment a valid GitHub token is provided instead of relying on the default value. A token value of"blank"will cause the GitHub API features to fail.
- File Reference:
blt/settings.pydefinesGITHUB_TOKENwithos.environ.get("GITHUB_TOKEN", "blank").- Action: Confirm that the production environment sets a valid token so all GitHub-related commands are authorized correctly.
- Added staff permission checks for the "refresh issues" and "pay bounty" actions in the BountyPayoutsView. - Updated bounty_payouts.html to conditionally display the refresh button for staff users only. - Implemented input escaping for various user-generated content to improve security and prevent XSS vulnerabilities.
- Updated the BountyPayoutsView to restrict payment processing to superusers, enhancing security. - Modified the bounty_payouts.html template to display a message for staff users indicating that only superusers can record payments.
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
🧹 Nitpick comments (6)
website/views/organization.py (3)
2660-2674: Consider adding a class-level permission check.Although the class-based design is clear, incorporating a decorator or mixin (e.g.,
@login_requiredorstaff_member_required) at the class level can simplify permission handling. This also ensures bounty payout pages remain accessible only to authorized users by default.
2768-2799: Refactor repeated logic in the “refresh_issues” action.The loop that creates/updates repos, contributors, and issues is lengthy and somewhat repetitive. Extract these steps into helper functions or methods for improved readability, maintainability, and testing.
2975-2989: Unify permission checks for payment actions.“pay_bounty” is currently restricted to staff, while “delete_issue” requires superuser rights. If both actions demand similar sensitivity, standardizing their permission checks can reduce confusion and maintain consistency.
website/templates/bounty_payouts.html (3)
58-62: Avoid hardcoded bounty computations.Using
multiply:5repeatedly implies a single fixed bounty value. If you plan to expand or alter the bounty, consider a dynamic or model-driven approach instead of embedding the numeric constant in template logic.
309-346: Reinforce transaction ID validation server-side.While the client-side regex checks for GitHub Sponsors and BCH transaction IDs are helpful, ensure the server also validates these. Relying solely on front-end filtering can lead to oversights if a user bypasses the JS.
461-482: Enhance user feedback when copying BCH addresses.Swapping the icon momentarily is useful but can be overlooked. Consider adding a small tooltip or toast message confirming the address was successfully copied for better user experience.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
website/templates/bounty_payouts.html(1 hunks)website/views/organization.py(1 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
website/views/organization.py (1)
website/models.py (10) (10)
GitHubIssue(1637-1825)Repo(1453-1530)Contributor(1078-1090)UserProfile(687-874)save(74-77)save(219-231)save(1121-1148)save(1256-1259)save(1500-1522)save(2187-2190)
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: Run Tests
- GitHub Check: Run Tests
- GitHub Check: docker-test
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: docker-test
🔇 Additional comments (2)
website/views/organization.py (2)
2800-2899: Double-check substring-based label parsing.Reliance on
'if "paid" in label_name'or'if "sponsors" in label_name'might lead to false positives if labels contain these substrings incidentally. Consider a stricter naming convention or exact matching to avoid unintended matches.
3043-3062: Validate references before deleting issues.Although superuser protection is in place, fully removing a bounty issue could impact reporting, payment history, or references in other models. Consider verifying that the issue is safe to remove or implementing a soft-delete if you need an audit trail.
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
🧹 Nitpick comments (4)
website/views/organization.py (4)
2662-2667: Add docstring or class-level comments for clarity.
Although each method inBountyPayoutsViewis individually documented, consider adding a short class-level docstring summarizing the view’s overall purpose.
2687-2725: Potential improvement: reduce repeated filtering.
Inget_context_data, you filter thebase_querysetmultiple times for paid or unpaid. You could centralize these counts in a single pass or use conditional aggregation to reduce repeated queries.
2726-2763: Add defensive checks for rate-limiting or partial results from GitHub.
Although you handle errors by returning an empty list upon failure, consider storing partial successes or warnings if only part of the data is fetched. This helps diagnose truncated results when GitHub imposes rate limits.
2923-3037: Consider splitting out GitHub issue creation logic.
This large block could be factored into a helper method (e.g.,create_or_update_issue_from_api) to improve readability and maintainability.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
website/templates/bounty_payouts.html(1 hunks)website/views/organization.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- website/templates/bounty_payouts.html
🧰 Additional context used
🧠 Learnings (1)
website/views/organization.py (1)
Learnt from: DonnieBLT
PR: OWASP-BLT/BLT#3990
File: website/views/organization.py:2779-2974
Timestamp: 2025-03-19T02:46:03.286Z
Learning: For the BountyPayoutsView and similar features, prioritize simplicity and functionality over premature optimization. Address performance optimizations like caching or bulk operations only if measurable slowness is observed in production.
🧬 Code Definitions (1)
website/views/organization.py (1)
website/models.py (10) (10)
GitHubIssue(1637-1825)Repo(1453-1530)Contributor(1078-1090)UserProfile(687-874)save(74-77)save(219-231)save(1121-1148)save(1256-1259)save(1500-1522)save(2187-2190)
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: Run Tests
- GitHub Check: Run Tests
- GitHub Check: docker-test
- GitHub Check: Analyze (python)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: docker-test
🔇 Additional comments (4)
website/views/organization.py (4)
2668-2686: Queryset filtering looks good!
The logic to filter by payment status (all, paid, unpaid) is straightforward and reads well.
2764-2775: Check permission consistency between refresh and pay actions.
Here you requirestafffor refresh, butsuperuserfor payout. If that’s intentional, it’s fine, but ensure consistent rationale (staff can refresh, but only superuser can pay).
2776-2880: Repeated contributor lookups match prior suggestions.
You create or update contributors on the fly. A previous review suggested caching or bulk-creating to avoid multiple GitHub calls (lines 2848-2872). The user indicated to skip it for now, so this remains acceptable.
2881-2922: Validate scoping for user profile update.
When linking a GitHub username to aUserProfile, confirm that partial matches or case differences won’t incorrectly link identities. A quick check for collisions or overwriting might be helpful.
Summary by CodeRabbit
New Features
Style