@@ -24,13 +24,71 @@ export interface CommunityEngagementScore {
2424 label : "Newcomer" | "Contributor" | "Collaborator" | "Community Champion" ;
2525}
2626
27+ const DISCUSSIONS_QUERY = `
28+ query CommunityEngagementDiscussions($from: DateTime!, $to: DateTime!) {
29+ viewer {
30+ contributionsCollection(from: $from, to: $to) {
31+ totalDiscussionContributions
32+ totalDiscussionCommentContributions
33+ }
34+ }
35+ }
36+ ` ;
37+
2738function scoreLabel ( total : number ) : CommunityEngagementScore [ "label" ] {
2839 if ( total >= 75 ) return "Community Champion" ;
2940 if ( total >= 50 ) return "Collaborator" ;
3041 if ( total >= 25 ) return "Contributor" ;
3142 return "Newcomer" ;
3243}
3344
45+ async function fetchDiscussionCount (
46+ token : string ,
47+ from : string ,
48+ to : string
49+ ) : Promise < number > {
50+ try {
51+ const response = await fetch ( "https://api.github.com/graphql" , {
52+ method : "POST" ,
53+ headers : {
54+ "Content-Type" : "application/json" ,
55+ Authorization : `Bearer ${ token } ` ,
56+ } ,
57+ body : JSON . stringify ( {
58+ query : DISCUSSIONS_QUERY ,
59+ variables : { from, to } ,
60+ } ) ,
61+ cache : "no-store" ,
62+ } ) ;
63+
64+ if ( ! response . ok ) return 0 ;
65+
66+ const json = ( await response . json ( ) ) as {
67+ data ?: {
68+ viewer ?: {
69+ contributionsCollection ?: {
70+ totalDiscussionContributions ?: number | null ;
71+ totalDiscussionCommentContributions ?: number | null ;
72+ } | null ;
73+ } | null ;
74+ } ;
75+ errors ?: Array < { message ?: string } > ;
76+ } ;
77+
78+ if ( json . errors ?. length ) return 0 ;
79+
80+ const collection = json . data ?. viewer ?. contributionsCollection ;
81+ if ( ! collection ) return 0 ;
82+
83+ return (
84+ ( collection . totalDiscussionContributions ?? 0 ) +
85+ ( collection . totalDiscussionCommentContributions ?? 0 )
86+ ) ;
87+ } catch {
88+ return 0 ;
89+ }
90+ }
91+
3492export async function GET ( req : NextRequest ) {
3593 const session = await getServerSession ( authOptions ) ;
3694 if ( ! session ?. accessToken || ! session . githubLogin ) {
@@ -40,6 +98,8 @@ export async function GET(req: NextRequest) {
4098 const since = new Date ( ) ;
4199 since . setDate ( since . getDate ( ) - 30 ) ;
42100 const sinceStr = since . toISOString ( ) . slice ( 0 , 10 ) ;
101+ const fromIso = since . toISOString ( ) ;
102+ const toIso = new Date ( ) . toISOString ( ) ;
43103
44104 const key = metricsCacheKey (
45105 session . githubId ?? session . githubLogin ,
@@ -56,8 +116,8 @@ export async function GET(req: NextRequest) {
56116 Accept : "application/vnd.github+json" ,
57117 } ;
58118
59- const [ reviewsRes , issuesOpenRes , issuesClosedRes , openSourceRes , docsRes ] =
60- await Promise . allSettled ( [
119+ const [ searchResults , discussions ] = await Promise . all ( [
120+ Promise . allSettled ( [
61121 fetch (
62122 `${ GITHUB_API } /search/issues?q=reviewed-by:${ session . githubLogin } +type:pr+updated:>=${ sinceStr } &per_page=1` ,
63123 { headers, cache : "no-store" }
@@ -78,7 +138,17 @@ export async function GET(req: NextRequest) {
78138 `${ GITHUB_API } /search/issues?q=author:${ session . githubLogin } +type:pr+is:merged+label:documentation+merged:>=${ sinceStr } &per_page=1` ,
79139 { headers, cache : "no-store" }
80140 ) ,
81- ] ) ;
141+ ] ) ,
142+ fetchDiscussionCount ( session . accessToken ! , fromIso , toIso ) ,
143+ ] ) ;
144+
145+ const [
146+ reviewsRes ,
147+ issuesOpenRes ,
148+ issuesClosedRes ,
149+ openSourceRes ,
150+ docsRes ,
151+ ] = searchResults ;
82152
83153 const getCount = async ( r : PromiseSettledResult < Response > ) => {
84154 if ( r . status !== "fulfilled" || ! r . value . ok ) return 0 ;
@@ -99,7 +169,7 @@ export async function GET(req: NextRequest) {
99169 const reviewPoints = Math . min ( reviews * 3 , 30 ) ;
100170 const issuesOpenedPoints = Math . min ( issuesOpened * 2 , 15 ) ;
101171 const issuesClosedPoints = Math . min ( issuesClosed * 3 , 20 ) ;
102- const discussionsPoints = 0 ; // placeholder — GitHub Discussions API requires GraphQL
172+ const discussionsPoints = Math . min ( discussions * 2 , 15 ) ;
103173 const openSourcePoints = Math . min ( openSourcePrs * 5 , 25 ) ;
104174 const documentationPoints = Math . min ( documentationPrs * 5 , 10 ) ;
105175
@@ -119,9 +189,12 @@ export async function GET(req: NextRequest) {
119189 reviews : { count : reviews , points : reviewPoints } ,
120190 issuesOpened : { count : issuesOpened , points : issuesOpenedPoints } ,
121191 issuesClosed : { count : issuesClosed , points : issuesClosedPoints } ,
122- discussions : { count : 0 , points : discussionsPoints } ,
192+ discussions : { count : discussions , points : discussionsPoints } ,
123193 openSourcePrs : { count : openSourcePrs , points : openSourcePoints } ,
124- documentationPrs : { count : documentationPrs , points : documentationPoints } ,
194+ documentationPrs : {
195+ count : documentationPrs ,
196+ points : documentationPoints ,
197+ } ,
125198 } ,
126199 label : scoreLabel ( total ) ,
127200 } ;
@@ -131,4 +204,4 @@ export async function GET(req: NextRequest) {
131204 ) ;
132205
133206 return Response . json ( data ) ;
134- }
207+ }
0 commit comments