Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
4238239
frontend: fetch project leaderboard data from backend API
Jayrodri088 Jan 23, 2026
cb04c34
Merge branch 'frontend/fetch-project-leaderboard-from-backend' of htt…
Jayrodri088 Jan 23, 2026
46fb3ad
fix: resolved conflicts
Jayrodri088 Jan 23, 2026
0f4dc16
Merge branch 'Jagadeeshftw:master' into frontend/fetch-project-leader…
Jayrodri088 Jan 23, 2026
d86cca7
fix: set env variables
Jayrodri088 Jan 23, 2026
99d813a
Merge branch 'frontend/fetch-project-leaderboard-from-backend' of htt…
Jayrodri088 Jan 23, 2026
ce5869f
frontend: mobile responsiveness for data page
Jayrodri088 Jan 23, 2026
7b6f696
fix: bugs in pages
Jayrodri088 Jan 24, 2026
d034d83
Merge branch 'master' into frontend/mobile-responsive-data-page
Jayrodri088 Jan 24, 2026
d37739e
fix: bugs in pages
Jayrodri088 Jan 24, 2026
fcfdbb8
fix: bugs
Jayrodri088 Jan 24, 2026
41394da
Merge branch 'frontend/mobile-responsive-data-page' of https://github…
Jayrodri088 Jan 25, 2026
ad52b6c
Merge branch 'frontend/fetch-project-leaderboard-from-backend' of htt…
Jayrodri088 Jan 25, 2026
68b5254
Merge branch 'frontend/fetch-project-leaderboard-from-backend' of htt…
Jayrodri088 Jan 27, 2026
6b3abd0
feat: add comprehensive test coverage and fuzzing
orsinibear Jan 27, 2026
dd6ef4d
Merge branch 'master' into feat/comprehensive-test-coverage
orsinibear Jan 28, 2026
2e7ebf4
Merge branch 'frontend/mobile-responsive-data-page' of https://github…
Jayrodri088 Jan 28, 2026
d7dcf47
maintaining other pages not relevant to this issue
Jayrodri088 Jan 28, 2026
e3cb553
Merge branch 'master' into feat/comprehensive-test-coverage
orsinibear Jan 28, 2026
ead4c2b
Merge branch 'master' into feat/comprehensive-test-coverage
Jagadeeshftw Jan 28, 2026
73e45cb
feat: add navigation from project profile Issues section to Issues pa…
Agbeleshe Jan 29, 2026
5e9b1c4
Merge branch 'Jagadeeshftw:master' into feat/comprehensive-test-coverage
orsinibear Jan 29, 2026
06b9c26
fix: close proptest macro delimiter
orsinibear Jan 29, 2026
e0193e5
feat: add navigation from project profile Issues section to Issues pa…
Agbeleshe Jan 29, 2026
a3851fa
Merge branch 'master' into project-navigation
Agbeleshe Jan 29, 2026
d17f2b4
Merge branch 'frontend/mobile-responsive-data-page' of https://github…
Jayrodri088 Jan 29, 2026
02adac9
Merge pull request #119 from Jayrodri088/frontend/mobile-responsive-d…
Jagadeeshftw Jan 29, 2026
3635d6a
Merge branch 'frontend/fetch-project-leaderboard-from-backend' of htt…
Jayrodri088 Jan 29, 2026
96cf6fd
Merge branch 'master' into feat/comprehensive-test-coverage
orsinibear Jan 29, 2026
929329e
Merge pull request #282 from Agbeleshe/project-navigation
Jagadeeshftw Jan 29, 2026
0d15f46
Merge branch 'master' into frontend/implement-functional-search-bar
Jagadeeshftw Jan 29, 2026
6d0450d
Merge pull request #286 from devJaja/frontend/implement-functional-se…
Jagadeeshftw Jan 29, 2026
2ad382b
frontend: add KYC verification icon to contributor profile header
ALIPHATICHYD Jan 24, 2026
09bf637
Merge upstream/master: resolve frontend/package.json conflict
ALIPHATICHYD Jan 29, 2026
e299683
Merge pull request #285 from ALIPHATICHYD/frontend/add-kyc-status-ico…
Jagadeeshftw Jan 29, 2026
1c66b4a
Merge branch 'frontend/fetch-project-leaderboard-from-backend' of htt…
Jayrodri088 Jan 29, 2026
0e3370d
admin config
Bosun-Josh121 Jan 29, 2026
ee56eb8
Merge pull request #87 from Jayrodri088/frontend/fetch-project-leader…
Jagadeeshftw Jan 29, 2026
4b3f0a5
feat: display multiple languages used in projects on project cards
Sendi0011 Jan 29, 2026
c1cb9fb
fix error
Bosun-Josh121 Jan 29, 2026
427ff83
fix error
Bosun-Josh121 Jan 29, 2026
ab86b9b
fix error
Bosun-Josh121 Jan 29, 2026
9021885
feat: implement partial payout functionality
Samaro1 Jan 29, 2026
42c8e1f
feat: implement partial payout functionality
Samaro1 Jan 29, 2026
be51301
feat: implement partial payout functionality
Samaro1 Jan 29, 2026
94d3f0a
feat(dashboard): add interval filtering for contributor activity charts
Macnelson9 Jan 29, 2026
e96d9eb
frontend: implement functional search with real projects, issues, and…
devJaja Jan 29, 2026
b4031c7
Merge branch 'master' into frontend/implement-functional-search-bar
devJaja Jan 29, 2026
03e534a
feat: merge incoming changes with current changes and implement contr…
Macnelson9 Jan 29, 2026
332bf34
Merge pull request #292 from Macnelson9/fix/contributor-activity-inte…
Jagadeeshftw Jan 29, 2026
349deb2
Merge pull request #291 from Samaro1/feat/partial-payout-support
Jagadeeshftw Jan 29, 2026
e2d712c
Merge pull request #289 from Sendi0011/feat/display-multiple-language…
Jagadeeshftw Jan 29, 2026
f6b2ef2
Merge pull request #288 from Bosun-Josh121/feat/admin-configuration
Jagadeeshftw Jan 29, 2026
d0d9dcb
Merge branch 'master' into feat/comprehensive-test-coverage
orsinibear Jan 29, 2026
9f9a311
fix: remove duplicate soroban-sdk dependency
orsinibear Jan 30, 2026
bae7edc
fix: Smart Contracts CI/CD workflow run failure
orsinibear Jan 31, 2026
0446254
Remove projects leaderboard endpoint
orsinibear Jan 31, 2026
deba3f5
removing code mix-up in the frontend
orsinibear Jan 31, 2026
50eab77
removing code mix-up in the frontend
orsinibear Jan 31, 2026
2a386ee
removing code mix-up in the frontend
orsinibear Jan 31, 2026
32fb395
removing code mix-up in the frontend
orsinibear Jan 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
!.elasticbeanstalk/*.global.yml
wasm_hash.txt

# Test Artifacts
**/test_snapshots/test_bounty_escrow/
**/test_snapshots/tests_external/
# Node modules
node_modules/

Expand Down
180 changes: 180 additions & 0 deletions backend/internal/handlers/leaderboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,183 @@ LIMIT $1 OFFSET $2
return c.Status(fiber.StatusOK).JSON(leaderboard)
}
}

// ProjectsLeaderboard returns top projects ranked by contributor count in verified projects
func (h *LeaderboardHandler) ProjectsLeaderboard() fiber.Handler {
return func(c *fiber.Ctx) error {
if h.db == nil || h.db.Pool == nil {
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "db_not_configured"})
}

// Get limit and offset from query params (default 10, max 100)
limit := c.QueryInt("limit", 10)
if limit < 1 {
limit = 10
}
if limit > 100 {
limit = 100
}
offset := c.QueryInt("offset", 0)
if offset < 0 {
offset = 0
}

// Get ecosystem filter (optional)
ecosystemSlug := c.Query("ecosystem", "")

// Build query with optional ecosystem filter
query := `
SELECT
p.id,
p.github_full_name,
(
SELECT COUNT(DISTINCT a.author_login)
FROM (
SELECT author_login FROM github_issues WHERE project_id = p.id AND author_login IS NOT NULL AND author_login != ''
UNION
SELECT author_login FROM github_pull_requests WHERE project_id = p.id AND author_login IS NOT NULL AND author_login != ''
) a
) AS contributors_count,
COALESCE(
(
SELECT ARRAY_AGG(DISTINCT e.name)
FROM ecosystems e
WHERE e.id = p.ecosystem_id AND e.status = 'active'
),
ARRAY[]::TEXT[]
) as ecosystems,
COALESCE(e.slug, '') as ecosystem_slug
FROM projects p
LEFT JOIN ecosystems e ON p.ecosystem_id = e.id
WHERE p.status = 'verified'
AND p.deleted_at IS NULL
AND (
SELECT COUNT(DISTINCT a.author_login)
FROM (
SELECT author_login FROM github_issues WHERE project_id = p.id AND author_login IS NOT NULL AND author_login != ''
UNION
SELECT author_login FROM github_pull_requests WHERE project_id = p.id AND author_login IS NOT NULL AND author_login != ''
) a
) > 0
`
args := []interface{}{}
argIndex := 1

// Add ecosystem filter if provided
if ecosystemSlug != "" {
query += fmt.Sprintf(" AND LOWER(e.slug) = LOWER($%d)", argIndex)
args = append(args, ecosystemSlug)
argIndex++
}

query += `
ORDER BY contributors_count DESC, p.github_full_name ASC
`

// Add limit and offset
query += fmt.Sprintf(" LIMIT $%d OFFSET $%d", argIndex, argIndex+1)
args = append(args, limit, offset)

rows, err := h.db.Pool.Query(c.Context(), query, args...)
if err != nil {
slog.Error("failed to fetch project leaderboard",
"error", err,
)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "project_leaderboard_fetch_failed"})
}
defer rows.Close()

var leaderboard []fiber.Map
rank := offset + 1 // Start rank from offset + 1 for pagination
for rows.Next() {
var id string
var fullName string
var contributorsCount int
var ecosystems []string
var ecosystemSlug string

if err := rows.Scan(&id, &fullName, &contributorsCount, &ecosystems, &ecosystemSlug); err != nil {
slog.Error("failed to scan project leaderboard row",
"error", err,
)
continue
}

// Ensure ecosystems is not nil
if ecosystems == nil {
ecosystems = []string{}
}

// Extract project name from github_full_name (owner/repo -> repo)
projectName := fullName
if idx := len(fullName) - 1; idx >= 0 {
if slashIdx := len(fullName) - 1; slashIdx >= 0 {
for i := len(fullName) - 1; i >= 0; i-- {
if fullName[i] == '/' {
projectName = fullName[i+1:]
break
}
}
}
}

// Generate a simple logo/icon based on project name (first letter or emoji)
// In a real implementation, you might want to fetch the actual repo avatar from GitHub
logo := "📦" // Default icon
if len(projectName) > 0 {
firstChar := projectName[0]
// Use emoji based on first letter (simple mapping)
emojiMap := map[byte]string{
'a': "🅰", 'b': "🅱", 'c': "©", 'd': "♦", 'e': "⚡",
'f': "⚡", 'g': "🎮", 'h': "🏠", 'i': "ℹ", 'j': "🎯",
'k': "🔑", 'l': "🔗", 'm': "📱", 'n': "🔢", 'o': "⭕",
'p': "📦", 'q': "❓", 'r': "🔴", 's': "⭐", 't': "🔧",
'u': "⬆", 'v': "✅", 'w': "🌐", 'x': "❌", 'y': "⚛",
'z': "⚡",
}
lowerChar := firstChar
if lowerChar >= 'A' && lowerChar <= 'Z' {
lowerChar = lowerChar + ('a' - 'A')
}
if emoji, ok := emojiMap[lowerChar]; ok {
logo = emoji
}
}

// Calculate activity level based on contributor count
activity := "Low"
if contributorsCount >= 200 {
activity = "Very High"
} else if contributorsCount >= 150 {
activity = "High"
} else if contributorsCount >= 100 {
activity = "Medium"
}

// Score is based on contributor count (can be enhanced with other metrics)
score := contributorsCount * 10 // Multiply by 10 to get a more meaningful score

leaderboard = append(leaderboard, fiber.Map{
"rank": rank,
"name": projectName,
"full_name": fullName,
"logo": logo,
"score": score,
"trend": "same", // For now, set to 'same' (can be enhanced with historical data)
"trendValue": 0,
"contributors": contributorsCount,
"ecosystems": ecosystems,
"activity": activity,
"project_id": id,
})
rank++
}

// Always return an array, even if empty
if leaderboard == nil {
leaderboard = []fiber.Map{}
}

return c.Status(fiber.StatusOK).JSON(leaderboard)
}
}
Loading