-
Notifications
You must be signed in to change notification settings - Fork 57
API integration for frontend #432
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ | |
|
|
||
| from app.auth import get_current_user_id | ||
| from app.constants import INTERNAL_SYSTEM_USER_ID | ||
| from app.exceptions import ContributorNotFoundError, TierNotUnlockedError | ||
|
Check failure on line 14 in backend/app/api/contributors.py
|
||
| from app.models.contributor import ( | ||
| ContributorCreate, | ||
| ContributorListResponse, | ||
|
|
@@ -254,5 +254,59 @@ | |
| return await reputation_service.record_reputation(data) | ||
| except ContributorNotFoundError as error: | ||
| raise HTTPException(status_code=404, detail=str(error)) | ||
| except TierNotUnlockedError as error: | ||
| raise HTTPException(status_code=400, detail=str(error)) | ||
| class DashboardData(BaseModel): | ||
|
Check failure on line 257 in backend/app/api/contributors.py
|
||
| """Payload for the contributor dashboard.""" | ||
| stats: dict | ||
| bounties: list | ||
| activities: list | ||
| notifications: list = [] | ||
| earnings: list = [] | ||
| linkedAccounts: list = [] | ||
|
|
||
|
|
||
| @router.get("/me/dashboard", response_model=DashboardData) | ||
| async def get_my_dashboard( | ||
| user_id: str = Depends(get_current_user_id) | ||
| ) -> DashboardData: | ||
|
Comment on lines
+267
to
+270
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainπ Script executed: #!/bin/bash
# Verify route ordering in contributors.py - /me/dashboard should come before /{contributor_id}
rg -n "@router\.(get|post|patch|delete)" backend/app/api/contributors.py | head -20Repository: SolFoundry/solfoundry Length of output: 663 π Script executed: # Check the context around the /{contributor_id} route and /me/dashboard route
sed -n '105,115p' backend/app/api/contributors.py
echo "---"
sed -n '263,275p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 712 π Script executed: # Check if there are any tests for the /me/dashboard endpoint
find . -type f -name "*.py" | xargs grep -l "me/dashboard\|/me.*dashboard" | head -10Repository: SolFoundry/solfoundry Length of output: 98 π Script executed: # Check the router setup and any middleware
head -50 backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 1656 π Script executed: # Look for any tests that actually test the /me/dashboard endpoint
find . -type f -name "test_*.py" -o -name "*_test.py" | xargs grep -l "dashboard\|me.*dashboard" 2>/dev/nullRepository: SolFoundry/solfoundry Length of output: 143 π Script executed: # Check the complete route definitions to understand path matching context
sed -n '100,280p' backend/app/api/contributors.py | cat -nRepository: SolFoundry/solfoundry Length of output: 6989 π Script executed: # Verify how the router is initialized and if there are any special configs
grep -n "router.*=" backend/app/api/contributors.py | head -5Repository: SolFoundry/solfoundry Length of output: 420 π Script executed: # Check if there are any tests specifically for the /me/dashboard route
grep -r "me/dashboard" backend/tests/ --include="*.py"Repository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Verify the exact line numbers for the routes in question
sed -n '105,115p' backend/app/api/contributors.py | cat -n
echo "---"
sed -n '165,175p' backend/app/api/contributors.py | cat -nRepository: SolFoundry/solfoundry Length of output: 798 π Script executed: # Check if this endpoint is actually being tested anywhere
grep -r "get_my_dashboard" backend/tests/ --include="*.py"Repository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Check if there's a test file for the contributors API
find backend/tests -name "*contributor*" -type fRepository: SolFoundry/solfoundry Length of output: 99 π Script executed: # Look for any test that makes a request to /{contributor_id}
grep -r "/{contributor_id}" backend/ --include="*.py" -B 2 -A 2Repository: SolFoundry/solfoundry Length of output: 1904 π Script executed: # Search for actual integration tests or any tests that would exercise these routes
find backend/tests -name "test_*.py" | head -5 | xargs cat | grep -A 5 "contributors"Repository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Check if DashboardData model is properly imported where the route is defined
sed -n '1,30p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 943 π Script executed: # Check the test file to see if /me/dashboard is being tested
cat backend/tests/test_contributors.pyRepository: SolFoundry/solfoundry Length of output: 11770 π Script executed: # Verify the exact content around the DashboardData and /me/dashboard route
sed -n '155,180p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 803 π Script executed: # Check if DashboardData is properly imported/defined in the file
grep -n "class DashboardData\|from.*DashboardData\|import.*DashboardData" backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 100 π Script executed: # Look for any base model import
grep -n "BaseModel\|from pydantic" backend/app/api/contributors.py | head -5Repository: SolFoundry/solfoundry Length of output: 100 π Script executed: # Check if there are any router configuration or middleware that might affect route matching
grep -rn "router.*=" backend/app/ --include="*.py" | grep -i contribRepository: SolFoundry/solfoundry Length of output: 1064 π Script executed: # Verify the actual line numbers more carefully
nl -ba backend/app/api/contributors.py | sed -n '105,115p'
echo "---SEPARATOR---"
nl -ba backend/app/api/contributors.py | sed -n '263,273p'Repository: SolFoundry/solfoundry Length of output: 179 π Script executed: # Check if there are any integration tests or acceptance tests that would test the full path
find backend/tests -name "*.py" -type f -exec grep -l "me/dashboard\|/api/contributors/me" {} \;Repository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Look for any documentation or API spec that documents this endpoint
find . -name "*.md" -o -name "*.openapi*" -o -name "*.swagger*" | xargs grep -l "me/dashboard" 2>/dev/null | head -5Repository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Get the complete file and check the exact context around both routes
sed -n '100,120p' backend/app/api/contributors.py
echo "---DIVIDER---"
sed -n '250,275p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 1438 π Script executed: # Look for how the main app is configured and if there's anything special about routing
sed -n '1,30p' backend/app/main.pyRepository: SolFoundry/solfoundry Length of output: 1461 π Script executed: # Search for any existing route tests that would test the /me pattern
grep -n "test.*me\|/me" backend/tests/test_contributors.pyRepository: SolFoundry/solfoundry Length of output: 286 π Script executed: # Verify the actual behavior by checking if there's any documentation or comments about route matching
grep -B 5 -A 5 "/me/dashboard" backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 381 π Script executed: # Check if this route is actually working or if there are any known issues
grep -r "dashboard" backend/ --include="*.py" | grep -i "test\|issue\|fixme\|todo" | head -10Repository: SolFoundry/solfoundry Length of output: 256 π Script executed: # Verify by creating a minimal test to check path matching behavior
python3 << 'EOF'
# Simulate FastAPI route matching behavior
paths_to_test = [
"/contributors/me",
"/contributors/me/dashboard",
"/contributors/alice",
"/contributors/some-uuid-123",
]
# Pattern: /{contributor_id} matches single segment only
single_segment_pattern = r"^/contributors/([^/]+)$"
# Pattern: /me/dashboard matches two segments
multi_segment_pattern = r"^/contributors/me/dashboard$"
import re
print("Single segment pattern /{contributor_id}:")
for path in paths_to_test:
match = re.match(single_segment_pattern, path)
print(f" {path}: {'MATCH' if match else 'NO MATCH'}")
print("\nMulti segment pattern /me/dashboard:")
for path in paths_to_test:
match = re.match(multi_segment_pattern, path)
print(f" {path}: {'MATCH' if match else 'NO MATCH'}")
EOFRepository: SolFoundry/solfoundry Length of output: 412 π Script executed: # Check if BaseModel is imported at the top of the file
head -30 backend/app/api/contributors.py | grep -i "pydantic\|basemodel"Repository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Get the complete imports section
sed -n '1,50p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 1656 π Script executed: # Verify if the endpoint is incomplete or has syntax errors
sed -n '257,290p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 1131 π Script executed: # Check if BaseModel is imported anywhere in the file (maybe as part of a wildcard import)
grep -n "from pydantic\|import.*BaseModel\|from.*models" backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 143 π Script executed: # Check the models.contributor module to see if BaseModel is re-exported
grep -n "BaseModel" backend/app/models/contributor.py | head -5Repository: SolFoundry/solfoundry Length of output: 263 π Script executed: # Check what's actually imported from app.models.contributor
sed -n '15,23p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 295 π Script executed: # Verify if BaseModel is missing from the imports in contributors.py
rg "^from pydantic import|^import.*BaseModel" backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Look at the complete DashboardData definition and the imports just before it
sed -n '245,280p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry Length of output: 1164 π Script executed: # Final verification: Check if there's a __init__.py or any wildcard imports that could export BaseModel
grep -r "from pydantic import.*\*\|__all__.*BaseModel" backend/app/ --include="*.py" | head -5Repository: SolFoundry/solfoundry Length of output: 47 π Script executed: # Check if the file can even be imported (syntax check)
python3 -c "import sys; sys.path.insert(0, 'backend'); from app.api.contributors import router; print('Import successful')" 2>&1 | head -20Repository: SolFoundry/solfoundry Length of output: 332 π Script executed: # Check the exact imports more carefully and see if BaseModel might be available indirectly
sed -n '1,30p' backend/app/api/contributors.py | cat -nRepository: SolFoundry/solfoundry Length of output: 1153 π Script executed: # Verify the complete import section including any missed lines
sed -n '1,60p' backend/app/api/contributors.py | grep -E "^from|^import"Repository: SolFoundry/solfoundry Length of output: 456 Missing The Note: The route ordering concern is unfounded. FastAPI's path matching correctly distinguishes between π€ Prompt for AI Agents |
||
| """Get metrics and state for the authenticated contributor's dashboard. | ||
|
|
||
| Args: | ||
| user_id: Authenticated user (contributor) ID. | ||
|
|
||
| Returns: | ||
| Structured dashboard data with stats, bounties, and activity history. | ||
|
|
||
| Raises: | ||
| HTTPException 404: Contributor profile not found. | ||
| """ | ||
| contributor = await contributor_service.get_contributor(user_id) | ||
| if not contributor: | ||
| raise HTTPException(status_code=404, detail="Contributor profile not found") | ||
|
|
||
| # In a real app, query database/indexers for these lists | ||
| stats = { | ||
| "totalEarned": contributor.total_earnings, | ||
| "activeBounties": 2, # Mocked count | ||
| "pendingPayouts": 0, | ||
| "reputationRank": 15, | ||
| "totalContributors": 120, | ||
| } | ||
|
|
||
| bounties = [ | ||
| {"id": "b1", "title": "Implement API Rate Limiting", "reward": 500, "deadline": "2026-03-30", "status": "in_progress", "progress": 75}, | ||
| {"id": "b2", "title": "Refactor Frontend Hooks", "reward": 300, "deadline": "2026-03-29", "status": "claimed", "progress": 10}, | ||
| ] | ||
|
|
||
| activities = [ | ||
| {"id": "a1", "type": "payout", "title": "Payout Received", "description": "Earned 500 $FNDRY for rate limiter", "timestamp": "2026-03-21T10:00:00Z", "amount": 500}, | ||
| {"id": "a2", "type": "pr_submitted", "title": "PR Submitted", "description": "Submitted PR for security middleware", "timestamp": "2026-03-21T09:00:00Z"}, | ||
| ] | ||
|
Comment on lines
+286
to
+303
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dashboard endpoint returns hardcoded mock data. The Do you want me to help design the database queries to fetch real bounty and activity data for the authenticated contributor? π€ Prompt for AI Agents |
||
|
|
||
| return DashboardData( | ||
| stats=stats, | ||
| bounties=bounties, | ||
| activities=activities, | ||
| notifications=[], | ||
| earnings=[], | ||
| linkedAccounts=[{"type": "github", "username": contributor.username, "connected": True}], | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ | |
| import logging | ||
| import time | ||
| from datetime import datetime, timezone | ||
| from typing import Dict, List, Optional | ||
|
Check failure on line 10 in backend/app/api/stats.py
|
||
|
|
||
| from fastapi import APIRouter | ||
| from pydantic import BaseModel | ||
|
|
@@ -135,7 +135,36 @@ | |
| return data | ||
|
|
||
|
|
||
| @router.get("/api/stats", response_model=StatsResponse) | ||
| class TokenomicsData(BaseModel): | ||
| """Tokenomics data response.""" | ||
| tokenName: str = "$FNDRY" | ||
| tokenCA: str = "Fndry...1H7" | ||
| totalSupply: int = 1_000_000_000 | ||
| circulatingSupply: int = 420_000_000 | ||
| treasuryHoldings: int = 250_000_000 | ||
| totalDistributed: int = 150_000_000 | ||
| totalBuybacks: int = 50_000_000 | ||
| totalBurned: int = 30_000_000 | ||
| feeRevenueSol: float = 1245.50 | ||
| distributionBreakdown: Dict[str, int] = { | ||
| "Circulating": 420_000_000, | ||
| "Treasury": 250_000_000, | ||
| "Staking": 200_000_000, | ||
| "Team_Vested": 100_000_000, | ||
| "Burned": 30_000_000, | ||
| } | ||
| lastUpdated: str = datetime.now(timezone.utc).isoformat() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Proposed fix class TokenomicsData(BaseModel):
"""Tokenomics data response."""
tokenName: str = "$FNDRY"
# ... other fields ...
- lastUpdated: str = datetime.now(timezone.utc).isoformat()
+ lastUpdated: Optional[str] = None
`@router.get`("/stats/tokenomics", response_model=TokenomicsData)
async def get_tokenomics() -> TokenomicsData:
"""Get tokenomics statistics for $FNDRY."""
- return TokenomicsData()
+ return TokenomicsData(lastUpdated=datetime.now(timezone.utc).isoformat())π€ Prompt for AI Agents |
||
|
|
||
|
|
||
| class TreasuryStats(BaseModel): | ||
| """Treasury stats response.""" | ||
| solBalance: float = 1245.50 | ||
| fndryBalance: int = 250_000_000 | ||
| totalPayouts: int = 1240 | ||
| treasuryWallet: str = "6v...m7p" | ||
|
Comment on lines
+138
to
+164
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§Ή Nitpick | π΅ Trivial Tokenomics and treasury endpoints return hardcoded placeholder data. Similar to the dashboard endpoint, these endpoints return static mock data rather than querying real blockchain/indexer sources. The inline comments acknowledge this limitation. For a complete API integration, consider implementing actual data fetching or clearly documenting these as placeholder endpoints that require future implementation. π€ Prompt for AI Agents |
||
|
|
||
|
|
||
| @router.get("/stats", response_model=StatsResponse) | ||
| async def get_stats() -> StatsResponse: | ||
| """Get bounty program statistics. | ||
|
|
||
|
|
@@ -151,4 +180,18 @@ | |
| Cached for 5 minutes. | ||
| """ | ||
| data = _get_cached_stats() | ||
| return StatsResponse(**data) | ||
| return StatsResponse(**data) | ||
|
|
||
|
|
||
| @router.get("/stats/tokenomics", response_model=TokenomicsData) | ||
| async def get_tokenomics() -> TokenomicsData: | ||
| """Get tokenomics statistics for $FNDRY.""" | ||
| # In a real app, this would query the blockchain/indexers | ||
| return TokenomicsData() | ||
|
|
||
|
|
||
| @router.get("/stats/treasury", response_model=TreasuryStats) | ||
| async def get_treasury() -> TreasuryStats: | ||
| """Get treasury wallet statistics.""" | ||
| # In a real app, this would query the treasury wallet address | ||
| return TreasuryStats() | ||
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.
Backend
DashboardDataschema mismatches frontendDashboardDatainterface.The backend returns
stats,bounties,activities,notifications,earnings,linkedAccounts, but the frontend interface infrontend/src/types/dashboard.tsexpectssummary,activeBounties,earnings(asEarningsSummary),recentActivity,notifications, andsettings(containinglinkedAccounts). This contract mismatch will cause runtime errors or incorrect UI rendering when the frontend consumes this endpoint.π€ Prompt for AI Agents
π§© Analysis chain
π Script executed:
Repository: SolFoundry/solfoundry
Length of output: 47
π Script executed:
Repository: SolFoundry/solfoundry
Length of output: 809
π Script executed:
rg -n "from app.models" backend/app/api/contributors.pyRepository: SolFoundry/solfoundry
Length of output: 143
π Script executed:
cat -n backend/app/models/contributor.py | head -30Repository: SolFoundry/solfoundry
Length of output: 1023
π Script executed:
sed -n '250,270p' backend/app/api/contributors.pyRepository: SolFoundry/solfoundry
Length of output: 714
π Script executed:
rg -n "class DashboardData" backend/app/api/contributors.py -A 10Repository: SolFoundry/solfoundry
Length of output: 389
π Script executed:
Repository: SolFoundry/solfoundry
Length of output: 228
Missing
BaseModelimport will cause runtimeNameError.The
DashboardDataclass at line 257 inherits fromBaseModel, butpydantic.BaseModelis never imported inbackend/app/api/contributors.py. The file imports specific classes fromapp.models.contributor(lines 15-20) but notBaseModel. This will cause aNameErrorwhen the module loads.Add to the import section:
from pydantic import BaseModelπ€ Prompt for AI Agents