diff --git a/api/src/app/controllers/github/index.ts b/api/src/app/controllers/github/index.ts index cb1baa8fb..fcaac53e4 100644 --- a/api/src/app/controllers/github/index.ts +++ b/api/src/app/controllers/github/index.ts @@ -128,21 +128,3 @@ export const listWatchersByRepository = async (req: Request, res: Response) => { return res.sendStatus(400); } }; - -export const getGithubUserByUsername = async (req: Request, res: Response) => { - try { - const githubUser = await Github.getUser({ - username: req.params.username, - }); - const { name, avatar_url, login, html_url } = githubUser; - return res.status(200).json({ - name: name, - avatar_url: avatar_url, - login: login, - html_url: html_url, - }); - } catch (e) { - console.log(e); - return res.sendStatus(400); - } -}; diff --git a/api/src/app/index.ts b/api/src/app/index.ts index 0d182be81..b811c702f 100644 --- a/api/src/app/index.ts +++ b/api/src/app/index.ts @@ -7,6 +7,7 @@ import Container from "typedi"; import { ContributorController } from "../contributor/controller"; import { DocsMiddleware } from "./middlewares/docs"; import { ErrorMiddleware } from "./middlewares/error"; +import { GithubUserController } from "../github-user/controller"; import { LoggerMiddleware } from "./middlewares/logger"; import { LoggerService } from "../logger/service"; import { SecurityMiddleware } from "./middlewares/security"; @@ -18,7 +19,7 @@ useContainer(Container); // Create the app: export const routingControllersOptions = { - controllers: [ContributorController], + controllers: [ContributorController, GithubUserController], middlewares: [ // middlewares: SecurityMiddleware, diff --git a/api/src/app/routes/api/github/index.ts b/api/src/app/routes/api/github/index.ts index e9d17e032..c71ca0f75 100644 --- a/api/src/app/routes/api/github/index.ts +++ b/api/src/app/routes/api/github/index.ts @@ -1,6 +1,5 @@ import express, { Router } from "express"; import { - getGithubUserByUsername, listBranchesByRepository, listCommitsByRepository, listForksByRepository, @@ -23,6 +22,5 @@ router.get("/issues/:repo", listIssuesByRepository); router.get("/count-starts/:repo", listStarsByRepository); router.get("/stargazers/:repo/:page", listStargazersByRepository); router.get("/watchers/:repo", listWatchersByRepository); -router.get("/user/:username", getGithubUserByUsername); export default router; diff --git a/api/src/app/services/github/index.ts b/api/src/app/services/github/index.ts index 2546024b3..19c6131fd 100644 --- a/api/src/app/services/github/index.ts +++ b/api/src/app/services/github/index.ts @@ -212,15 +212,3 @@ export const listWatchers = async ({ return null; } }; - -export const getUser = async ({ username }: { username: string }) => { - try { - const response = await axios.get( - `https://api.github.com/users/${username}`, - ); - return response.data; - } catch (error) { - console.log("getUser =>", error.response.data); - return null; - } -}; diff --git a/api/src/github-user/controller.ts b/api/src/github-user/controller.ts new file mode 100644 index 000000000..7ec059088 --- /dev/null +++ b/api/src/github-user/controller.ts @@ -0,0 +1,28 @@ +import { Controller, Get, Param } from "routing-controllers"; +import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; +import { GetUserResponseDto } from "./types"; +import { GithubService } from "../github/service"; +import { Service } from "typedi"; + +@Service() +@Controller("/GithubUsers") +export class GithubUserController { + constructor(private readonly githubService: GithubService) {} + + @Get("/:username") + @OpenAPI({ + summary: "Return a github user with publicly available information", + }) + @ResponseSchema(GetUserResponseDto) + public async getUserByUsername( + @Param("username") username: string, + ): Promise { + const user = await this.githubService.getUser({ + username, + }); + + return { + user, + }; + } +} diff --git a/api/src/github-user/types.ts b/api/src/github-user/types.ts new file mode 100644 index 000000000..380a56d52 --- /dev/null +++ b/api/src/github-user/types.ts @@ -0,0 +1,8 @@ +import { GeneralResponseDto } from "../app/types"; +import { GithubUserDto } from "../github/dto"; +import { ValidateNested } from "class-validator"; + +export class GetUserResponseDto extends GeneralResponseDto { + @ValidateNested() + user?: GithubUserDto; +} diff --git a/api/src/github/dto.ts b/api/src/github/dto.ts index a6aee61ce..9197ac18b 100644 --- a/api/src/github/dto.ts +++ b/api/src/github/dto.ts @@ -1,13 +1,13 @@ +import { IsNumber, IsString } from "class-validator"; import { GithubUser } from "@dzcode.io/common/dist/types"; -import { IsString } from "class-validator"; export class GithubUserDto implements GithubUser { @IsString() avatar_url!: string; // eslint-disable-line camelcase @IsString() html_url!: string; // eslint-disable-line camelcase - @IsString() - id!: string; + @IsNumber() + id!: number; @IsString() login!: string; @IsString() diff --git a/api/src/github/service.ts b/api/src/github/service.ts index 63d493776..75413d838 100644 --- a/api/src/github/service.ts +++ b/api/src/github/service.ts @@ -1,4 +1,9 @@ -import { GeneralGithubQuery, ListContributorsResponse } from "./types"; +import { + GeneralGithubQuery, + GetUserInput, + GitHubUserApiResponse, + ListContributorsResponse, +} from "./types"; import { Service } from "typedi"; import axios from "axios"; @@ -28,5 +33,14 @@ export class GithubService { return contributors; }; + public getUser = async ({ + username, + }: GetUserInput): Promise => { + const response = await axios.get( + `${this.apiURL}/users/${username}`, + ); + return response.data; + }; + private apiURL = "https://api.github.com"; } diff --git a/api/src/github/types.ts b/api/src/github/types.ts index 864d5deb0..0f15f0ee8 100644 --- a/api/src/github/types.ts +++ b/api/src/github/types.ts @@ -10,3 +10,43 @@ export interface GeneralGithubQuery { repo: string; path: string; } + +export interface GetUserInput { + username: string; +} + +/* eslint-disable camelcase */ +export interface GitHubUserApiResponse { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + name: string; + company: string; + blog: string; + location: string; + email: string; + hireable: boolean; + bio: string; + twitter_username: string; + public_repos: number; + public_gists: number; + followers: number; + following: number; + created_at: string; + updated_at: string; +} diff --git a/api/test/mocks.ts b/api/test/mocks.ts index e313dbf59..f3cc7b63b 100644 --- a/api/test/mocks.ts +++ b/api/test/mocks.ts @@ -3,7 +3,7 @@ import { GithubUser } from "@dzcode.io/common/dist/types"; export const githubUserMock: GithubUser = { avatar_url: "avatar_url", // eslint-disable-line camelcase html_url: "html_url", // eslint-disable-line camelcase - id: "id", + id: 1, login: "login", type: "type", }; @@ -11,7 +11,7 @@ export const githubUserMock: GithubUser = { export const githubUserMock2: GithubUser = { avatar_url: "avatar_url2", // eslint-disable-line camelcase html_url: "html_url2", // eslint-disable-line camelcase - id: "id2", + id: 2, login: "login2", type: "type2", }; @@ -19,7 +19,7 @@ export const githubUserMock2: GithubUser = { export const githubUserMock3: GithubUser = { avatar_url: "avatar_url3", // eslint-disable-line camelcase html_url: "html_url3", // eslint-disable-line camelcase - id: "id3", + id: 3, login: "login3", type: "type3", }; diff --git a/common/src/types/index.ts b/common/src/types/index.ts index b91d8b61b..b0da700b5 100644 --- a/common/src/types/index.ts +++ b/common/src/types/index.ts @@ -40,7 +40,7 @@ export type Environment = "development" | "staging" | "production"; export interface GithubUser { login: string; - id: string; + id: number; // eslint-disable-next-line camelcase avatar_url: string; // eslint-disable-next-line camelcase diff --git a/web/src/apps/main/redux/actions/articles-page/index.ts b/web/src/apps/main/redux/actions/articles-page/index.ts index eacbe9e18..5f65e019a 100644 --- a/web/src/apps/main/redux/actions/articles-page/index.ts +++ b/web/src/apps/main/redux/actions/articles-page/index.ts @@ -98,7 +98,7 @@ const fetchCurrentArticleAuthors = (): ThunkResult< const githubAuthors = ( await Promise.all( currentArticle.authors?.map((author) => { - return Axios.get(apiURL + `/github/user/${author}`); + return Axios.get(apiURL + `/v2/GithubUsers/${author}`); }) || [], ) ).map((response) => { diff --git a/web/src/apps/main/redux/actions/documentation-page/index.ts b/web/src/apps/main/redux/actions/documentation-page/index.ts index d0db6859e..01d9541f8 100644 --- a/web/src/apps/main/redux/actions/documentation-page/index.ts +++ b/web/src/apps/main/redux/actions/documentation-page/index.ts @@ -97,7 +97,7 @@ const fetchCurrentDocumentAuthors = (): ThunkResult< const githubAuthors = ( await Promise.all( currentDocument.authors?.map((author) => { - return Axios.get(apiURL + `/github/user/${author}`); + return Axios.get(apiURL + `/v2/GithubUsers/${author}`); }) || [], ) ).map((response) => {