Skip to content

Commit cbe2817

Browse files
authored
Merge pull request #348 from genlayer-foundation/fix-submissions-calls
Add comprehensive metrics dashboard for submissions and participants
2 parents 40b310f + 6047ae3 commit cbe2817

9 files changed

Lines changed: 773 additions & 139 deletions

File tree

backend/CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ GET /api/v1/leaderboard/user_stats/by-address/{address}/
186186
# Multipliers
187187
GET /api/v1/multipliers/
188188
GET /api/v1/multiplier-periods/
189+
190+
# Steward Submissions (public metrics)
191+
GET /api/v1/steward-submissions/stats/ (public - aggregate stats)
192+
GET /api/v1/steward-submissions/daily-metrics/ (public - time-series data)
189193
```
190194

191195
## Environment Variables

backend/api/metrics_views.py

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,11 @@ class ContributionTypesStatsView(APIView):
8585
"""
8686
Get time series data showing how many contribution types have been assigned on each date.
8787
"""
88-
88+
8989
def get(self, request):
9090
from django.db.models.functions import TruncDate
9191
from datetime import date, timedelta
92-
92+
9393
# Get contributions grouped by date and contribution type
9494
daily_contributions = (
9595
Contribution.objects
@@ -101,51 +101,119 @@ def get(self, request):
101101
)
102102
.order_by('date')
103103
)
104-
104+
105105
# Build cumulative data
106106
data = []
107107
cumulative_types = set()
108-
108+
109109
# Get all contributions to track cumulative unique types
110110
all_contributions = (
111111
Contribution.objects
112112
.values('contribution_date', 'contribution_type')
113113
.order_by('contribution_date')
114114
)
115-
115+
116116
# Group by date and count cumulative types
117117
from collections import defaultdict
118118
contributions_by_date = defaultdict(set)
119-
119+
120120
for contrib in all_contributions:
121121
date_key = contrib['contribution_date'].date()
122122
contributions_by_date[date_key].add(contrib['contribution_type'])
123-
123+
124124
if contributions_by_date:
125125
# Get date range
126126
start_date = min(contributions_by_date.keys())
127127
end_date = max(contributions_by_date.keys())
128-
128+
129129
# Extend to today if needed
130130
today = date.today()
131131
if end_date < today:
132132
end_date = today
133-
133+
134134
# Build continuous time series with cumulative count
135135
current_date = start_date
136-
136+
137137
while current_date <= end_date:
138138
# Add new types for this date
139139
if current_date in contributions_by_date:
140140
cumulative_types.update(contributions_by_date[current_date])
141-
141+
142142
data.append({
143143
'date': current_date.isoformat(),
144144
'count': len(cumulative_types),
145145
'new_types': len(contributions_by_date.get(current_date, set()))
146146
})
147-
147+
148148
# Move to next day
149149
current_date += timedelta(days=1)
150-
150+
151+
return Response({'data': data})
152+
153+
154+
class ParticipantsGrowthView(APIView):
155+
"""
156+
Get time series data for validators, waitlist users, and builders growth over time.
157+
"""
158+
159+
def get(self, request):
160+
from django.db.models.functions import TruncDate
161+
from datetime import date, timedelta
162+
from collections import defaultdict
163+
from validators.models import Validator
164+
from builders.models import Builder
165+
166+
# Get validators by creation date
167+
validators_by_date = defaultdict(int)
168+
for v in Validator.objects.all():
169+
date_key = v.created_at.date()
170+
validators_by_date[date_key] += 1
171+
172+
# Get waitlist users by contribution date (users with validator-waitlist contribution)
173+
waitlist_by_date = defaultdict(int)
174+
try:
175+
waitlist_type = ContributionType.objects.get(slug='validator-waitlist')
176+
for c in Contribution.objects.filter(contribution_type=waitlist_type):
177+
date_key = c.contribution_date.date()
178+
waitlist_by_date[date_key] += 1
179+
except ContributionType.DoesNotExist:
180+
pass
181+
182+
# Get builders by creation date
183+
builders_by_date = defaultdict(int)
184+
for b in Builder.objects.all():
185+
date_key = b.created_at.date()
186+
builders_by_date[date_key] += 1
187+
188+
# Find date range across all sources
189+
all_dates = set(validators_by_date.keys()) | set(waitlist_by_date.keys()) | set(builders_by_date.keys())
190+
191+
if not all_dates:
192+
return Response({'data': []})
193+
194+
start_date = min(all_dates)
195+
end_date = max(max(all_dates), date.today())
196+
197+
# Build cumulative time series
198+
data = []
199+
cum_validators = 0
200+
cum_waitlist = 0
201+
cum_builders = 0
202+
203+
current_date = start_date
204+
while current_date <= end_date:
205+
cum_validators += validators_by_date.get(current_date, 0)
206+
cum_waitlist += waitlist_by_date.get(current_date, 0)
207+
cum_builders += builders_by_date.get(current_date, 0)
208+
209+
data.append({
210+
'date': current_date.isoformat(),
211+
'validators': cum_validators,
212+
'waitlist': cum_waitlist,
213+
'builders': cum_builders,
214+
'total': cum_validators + cum_waitlist + cum_builders
215+
})
216+
217+
current_date += timedelta(days=1)
218+
151219
return Response({'data': data})

backend/api/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from contributions.views import ContributionTypeViewSet, ContributionViewSet, EvidenceViewSet, SubmittedContributionViewSet, StewardSubmissionViewSet, MissionViewSet, StartupRequestViewSet
55
from leaderboard.views import GlobalLeaderboardMultiplierViewSet, LeaderboardViewSet
66
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
7-
from .metrics_views import ActiveValidatorsView, ContributionTypesStatsView
7+
from .metrics_views import ActiveValidatorsView, ContributionTypesStatsView, ParticipantsGrowthView
88

99
# Create a router and register our viewsets with it
1010
router = DefaultRouter()
@@ -37,4 +37,5 @@
3737
# Metrics endpoints
3838
path('metrics/active-validators/', ActiveValidatorsView.as_view(), name='active-validators'),
3939
path('metrics/contribution-types/', ContributionTypesStatsView.as_view(), name='contribution-types-stats'),
40+
path('metrics/participants-growth/', ParticipantsGrowthView.as_view(), name='participants-growth'),
4041
]

0 commit comments

Comments
 (0)