forked from giscus/giscus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { NextApiRequest, NextApiResponse } from "next"; | ||
import { IError } from "../../../lib/types/adapter"; | ||
import { DiscussionQuery } from "../../../lib/types/common"; | ||
import { getAppAccessToken } from "../../../services/github/getAppAccessToken"; | ||
import { getDiscussionCommentsCount } from "../../../services/github/getDiscussionCommentsCount"; | ||
|
||
export default async function get(req: NextApiRequest, res: NextApiResponse<number | IError>) { | ||
const params: DiscussionQuery = { | ||
repo: req.query.repo as string, | ||
term: req.query.term as string, | ||
number: +req.query.number, | ||
category: req.query.category as string | ||
}; | ||
|
||
const userToken = req.headers.authorization?.split('Bearer ')[1]; | ||
let token = userToken; | ||
if (!token) { | ||
try { | ||
token = await getAppAccessToken(params.repo); | ||
} catch (error) { | ||
res.status(403).json({ error: error.message }); | ||
return; | ||
} | ||
} | ||
|
||
const response = await getDiscussionCommentsCount(params, token); | ||
|
||
if ('message' in response) { | ||
if (response.message.includes('Bad credentials')) { | ||
res.status(403).json({ error: response.message }); | ||
return; | ||
} | ||
res.status(500).json({ error: response.message }); | ||
return; | ||
} | ||
|
||
if ('errors' in response) { | ||
const error = response.errors[0]; | ||
if (error?.message?.includes('API rate limit exceeded')) { | ||
let message = `API rate limit exceeded for ${params.repo}`; | ||
if (!userToken) { | ||
message += '. Sign in to increase the rate limit'; | ||
} | ||
res.status(429).json({ error: message }); | ||
return; | ||
} | ||
|
||
console.error(response); | ||
const message = response.errors.map?.(({ message }) => message).join('. ') || 'Unknown error'; | ||
res.status(500).json({ error: message }); | ||
return; | ||
} | ||
|
||
const { data } = response; | ||
if (!data) { | ||
console.error(response); | ||
res.status(500).json({ error: 'Unable to fetch discussion' }); | ||
return; | ||
} | ||
|
||
const discussion = 'search' in data ? data.search.nodes[0] ?? null : data.repository.discussion; | ||
|
||
if (!discussion) { | ||
res.status(404).json({ error: 'Discussion not found' }); | ||
return; | ||
} | ||
|
||
|
||
res.setHeader('Cache-Control', 'public, s-maxage=3600, stale-while-revalidate=900, stale-if-error=86400'); | ||
res.status(200).json(discussion.comments.totalCount); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { DiscussionQuery } from '../../lib/types/common'; | ||
import { GError, GMultipleErrors, GRepositoryDiscussionCount } from '../../lib/types/github'; | ||
import { parseRepoWithOwner } from '../../lib/utils'; | ||
import { GITHUB_GRAPHQL_API_URL } from '../config'; | ||
|
||
const DISCUSSION_QUERY = ` | ||
comments { | ||
totalCount | ||
}`; | ||
|
||
const SEARCH_QUERY = ` | ||
search(type: DISCUSSION last: 1 query: $query) { | ||
nodes { | ||
... on Discussion { | ||
${DISCUSSION_QUERY} | ||
} | ||
} | ||
}`; | ||
|
||
const SPECIFIC_QUERY = ` | ||
repository(owner: $owner, name: $name) { | ||
discussion(number: $number) { | ||
${DISCUSSION_QUERY} | ||
} | ||
} | ||
`; | ||
|
||
const GET_DISCUSSION_QUERY = (type: 'term' | 'number') => ` | ||
query(${ | ||
type === 'term' ? '$query: String!' : '$owner: String! $name: String! $number: Int!' | ||
}) { | ||
${type === 'term' ? SEARCH_QUERY : SPECIFIC_QUERY} | ||
}`; | ||
|
||
export interface GetDiscussionCommentsCountParams extends DiscussionQuery {} | ||
|
||
interface SearchResponse { | ||
data: { | ||
search: { | ||
nodes: Array<GRepositoryDiscussionCount>; | ||
}; | ||
}; | ||
} | ||
|
||
interface SpecificResponse { | ||
data: { | ||
repository: { | ||
discussion: GRepositoryDiscussionCount; | ||
}; | ||
}; | ||
} | ||
|
||
type GetDiscussionCommentsCountResponse = SearchResponse | SpecificResponse; | ||
|
||
export async function getDiscussionCommentsCount( | ||
params: GetDiscussionCommentsCountParams, | ||
token: string, | ||
): Promise<GetDiscussionCommentsCountResponse | GError | GMultipleErrors> { | ||
const { repo: repoWithOwner, term, number, category, ...pagination } = params; | ||
|
||
// Force repo to lowercase to prevent GitHub's bug when using category in query. | ||
// https://github.com/giscus/giscus/issues/118 | ||
const repo = repoWithOwner.toLowerCase(); | ||
const categoryQuery = category ? `category:${JSON.stringify(category)}` : ''; | ||
const query = `repo:${repo} ${categoryQuery} in:title ${term}`; | ||
const gql = GET_DISCUSSION_QUERY(number ? 'number' : 'term'); | ||
|
||
return fetch(GITHUB_GRAPHQL_API_URL, { | ||
method: 'POST', | ||
headers: { Authorization: `Bearer ${token}` }, | ||
|
||
body: JSON.stringify({ | ||
query: gql, | ||
variables: { | ||
repo, | ||
query, | ||
number, | ||
...parseRepoWithOwner(repo), | ||
}, | ||
}), | ||
}).then((r) => r.json()); | ||
} |
fcc6fcc
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.
Successfully deployed to the following URLs: