Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: add draft for data module #28

Merged
merged 128 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
c5210c0
Feat: add draft for data module
HC-kang Oct 22, 2024
1cf4c52
fix: type erros with jest-dom
DaleSeo Oct 23, 2024
56e239f
ci: add integration workflow
DaleSeo Oct 23, 2024
3f79d97
chore: do not clutter test output with errors
DaleSeo Oct 23, 2024
02b602b
fix: global css for storybook
Sunjae95 Oct 23, 2024
31bbf09
Merge pull request #32 from DaleStudy/30-storybook-global-css
Sunjae95 Oct 23, 2024
feaaa8f
Merge pull request #29 from DaleStudy/ci-integration
DaleSeo Oct 23, 2024
38021c1
feat : implement progress component
SamTheKorean Oct 23, 2024
d8f96be
feat : implement progress story
SamTheKorean Oct 23, 2024
9f163b7
feat : implement progress test
SamTheKorean Oct 23, 2024
6fbfe7a
feat : implement index page
SamTheKorean Oct 23, 2024
e6590c1
fix : refactor test cases and remove unused dependancy
SamTheKorean Oct 25, 2024
d4639a7
Merge pull request #31 from DaleStudy/sam/create-progress-page
SamTheKorean Oct 25, 2024
2378ee2
fix : clean up css not required
SamTheKorean Oct 20, 2024
0c95ee6
feat : implement leaderboard component
SamTheKorean Oct 21, 2024
7069566
feat : implement story for leaderboard
SamTheKorean Oct 21, 2024
ed91ab0
feat : implement unit test for leaderboard
SamTheKorean Oct 21, 2024
f13112a
feat : implement index page
SamTheKorean Oct 23, 2024
8b0ba70
fix : refactor test and remove unused imports
SamTheKorean Oct 25, 2024
ee0c9cc
ci: add deployment workflow
DaleSeo Oct 25, 2024
86bb7ca
feat: clean up member data module
HC-kang Oct 26, 2024
f5dec9c
fix : apply feadback with test cases and htnl structure
SamTheKorean Oct 26, 2024
ddb16ec
fix: 데이터 모듈에서 동일한 멤버가 여러 팀에 속한 경우 중복 제거
HC-kang Oct 26, 2024
65f05cc
test: add test code for get data service and clients
HC-kang Oct 26, 2024
204e9de
refactor: move types to each directory
HC-kang Oct 26, 2024
2ffaef9
fix: data module type import error
HC-kang Oct 26, 2024
6a21ba6
remove: unused file
HC-kang Oct 26, 2024
fda3341
test: replace console error mock with spy
HC-kang Oct 26, 2024
9a43193
Merge pull request #34 from DaleStudy/ci-deployment
DaleSeo Oct 27, 2024
363ff4a
docs: contributing and pr template
DaleSeo Oct 27, 2024
969f60d
fix : adjust folder and filenames for convention
SamTheKorean Oct 28, 2024
0865793
Merge pull request #17 from DaleStudy/sam/create-leaderboard-page
SamTheKorean Oct 28, 2024
4230f14
test: Certificate page
Sunjae95 Oct 19, 2024
b8322bf
story: Certificate Page
Sunjae95 Oct 19, 2024
cf784b1
rename: certificate from src to components
Sunjae95 Oct 19, 2024
bfeba2d
fix: review apply
Sunjae95 Oct 19, 2024
a6c9946
Merge pull request #18 from DaleStudy/15-certificate-only-frame
Sunjae95 Oct 28, 2024
1798d60
Refactor: modify format and types without changing test cases
HC-kang Oct 28, 2024
8b50286
Merge pull request #40 from DaleStudy/docs-contributing
DaleSeo Oct 28, 2024
d2ee200
Refactor: encapsulate fetch client
HC-kang Oct 28, 2024
d405e1b
Rename: API_VERSION to MEDIA_TYPE
HC-kang Oct 28, 2024
e4af42b
Refactor: modify handle error function
HC-kang Oct 28, 2024
ef78a24
Test: enhance test cases
HC-kang Oct 28, 2024
21ee78c
separate documents and scripts per page
DaleSeo Oct 28, 2024
dfe5b0c
configure vite to support mpa
DaleSeo Oct 28, 2024
044e63b
deps: remove react-router-dom
DaleSeo Oct 29, 2024
d140a4d
feat: remove ErrorPage
DaleSeo Oct 29, 2024
c31a5b5
test: address broken tests
DaleSeo Oct 30, 2024
c33c3cd
remove progress folder
DaleSeo Oct 30, 2024
9f8b2d0
create Progress folder
DaleSeo Oct 30, 2024
212435d
Merge pull request #44 from DaleStudy/mpa
DaleSeo Oct 30, 2024
86e9e2c
remove: unused variables
HC-kang Oct 30, 2024
24866ca
feat: add attr to MemberInfo and rename GithubInfo to StudyInfo
HC-kang Oct 30, 2024
b7f5ab4
refactor: createMemberInfoMap function
HC-kang Oct 30, 2024
dd84127
fix: type import
HC-kang Nov 1, 2024
b47f411
remove: fetch client
HC-kang Nov 1, 2024
9cc85bf
simplify: github client
HC-kang Nov 1, 2024
0c2962d
simplify: member info service
HC-kang Nov 1, 2024
7d577ff
remove: legacy codes
HC-kang Nov 1, 2024
6c94c93
refactor: modify directory structure and divide types
HC-kang Nov 2, 2024
f36372b
test: add tests for modules
HC-kang Nov 2, 2024
4922cc5
feat: add store service
HC-kang Nov 2, 2024
3837225
test: fix side effects of type simplification
HC-kang Nov 2, 2024
b1eb0ed
test: add store service test
HC-kang Nov 2, 2024
b561ba1
feat: add store service local storage cache
HC-kang Nov 2, 2024
db3e480
feat: add hard refresh to get data
HC-kang Nov 2, 2024
a163cb3
chore: cleanup directory structure
HC-kang Nov 2, 2024
4946eaf
typo
HC-kang Nov 2, 2024
09a8ba8
rename: modify file name and remove cache
HC-kang Nov 2, 2024
38d492f
remove: renamed file
HC-kang Nov 2, 2024
90197a9
feat: add renamed file
HC-kang Nov 2, 2024
747d927
rename: rename file
HC-kang Nov 2, 2024
ec2c708
rename: rename file
HC-kang Nov 2, 2024
2d66dc7
rename: github directory
HC-kang Nov 2, 2024
4f57007
rename: gitHub directory
HC-kang Nov 2, 2024
bb3dc47
remove: caching feature in store service
HC-kang Nov 3, 2024
f7c7eb1
style: arrow to function for exported functions
HC-kang Nov 3, 2024
453464f
test: fix mock type safety
HC-kang Nov 3, 2024
6825e8d
remove: unused features
HC-kang Nov 3, 2024
1f3f11c
test: update test for feature change
HC-kang Nov 3, 2024
d814bca
refactor: apply review comments
HC-kang Nov 5, 2024
0d0747d
test: remove invalid cohort test
HC-kang Nov 5, 2024
b3ab1d4
Feat: add draft for data module
HC-kang Oct 22, 2024
98ff3cc
feat: clean up member data module
HC-kang Oct 26, 2024
7e8b9d2
fix: 데이터 모듈에서 동일한 멤버가 여러 팀에 속한 경우 중복 제거
HC-kang Oct 26, 2024
a25315f
test: add test code for get data service and clients
HC-kang Oct 26, 2024
1abdff9
refactor: move types to each directory
HC-kang Oct 26, 2024
2b9d62d
fix: data module type import error
HC-kang Oct 26, 2024
acbb811
remove: unused file
HC-kang Oct 26, 2024
3531a92
test: replace console error mock with spy
HC-kang Oct 26, 2024
606ef44
Refactor: modify format and types without changing test cases
HC-kang Oct 28, 2024
e2249dd
Refactor: encapsulate fetch client
HC-kang Oct 28, 2024
a2252ed
Rename: API_VERSION to MEDIA_TYPE
HC-kang Oct 28, 2024
0577a41
Refactor: modify handle error function
HC-kang Oct 28, 2024
6edad94
Test: enhance test cases
HC-kang Oct 28, 2024
8ac9720
remove: unused variables
HC-kang Oct 30, 2024
72f710b
feat: add attr to MemberInfo and rename GithubInfo to StudyInfo
HC-kang Oct 30, 2024
842aa44
refactor: createMemberInfoMap function
HC-kang Oct 30, 2024
a37e7a1
fix: type import
HC-kang Nov 1, 2024
d295ca2
remove: fetch client
HC-kang Nov 1, 2024
e78f71a
simplify: github client
HC-kang Nov 1, 2024
ce89bd5
simplify: member info service
HC-kang Nov 1, 2024
c28a759
remove: legacy codes
HC-kang Nov 1, 2024
0370bd0
refactor: modify directory structure and divide types
HC-kang Nov 2, 2024
fc49ddf
test: add tests for modules
HC-kang Nov 2, 2024
8f8c5a3
feat: add store service
HC-kang Nov 2, 2024
265f97b
test: fix side effects of type simplification
HC-kang Nov 2, 2024
8305e9b
test: add store service test
HC-kang Nov 2, 2024
57e9ff3
feat: add store service local storage cache
HC-kang Nov 2, 2024
2ae8ade
feat: add hard refresh to get data
HC-kang Nov 2, 2024
77ac38d
chore: cleanup directory structure
HC-kang Nov 2, 2024
e39bbde
typo
HC-kang Nov 2, 2024
2048e99
rename: modify file name and remove cache
HC-kang Nov 2, 2024
fadf497
remove: renamed file
HC-kang Nov 2, 2024
f4806d6
feat: add renamed file
HC-kang Nov 2, 2024
049de21
rename: rename file
HC-kang Nov 2, 2024
3319125
rename: rename file
HC-kang Nov 2, 2024
2498290
rename: github directory
HC-kang Nov 2, 2024
dd44373
rename: gitHub directory
HC-kang Nov 2, 2024
b298f45
remove: caching feature in store service
HC-kang Nov 3, 2024
1c4aae0
style: arrow to function for exported functions
HC-kang Nov 3, 2024
6f70aa0
test: fix mock type safety
HC-kang Nov 3, 2024
7bbd017
remove: unused features
HC-kang Nov 3, 2024
ff22c69
test: update test for feature change
HC-kang Nov 3, 2024
618236a
refactor: apply review comments
HC-kang Nov 5, 2024
b7ef969
test: remove invalid cohort test
HC-kang Nov 5, 2024
dafdbfd
typo: 오탈자 수정
HC-kang Nov 7, 2024
31e28ac
Merge branch 'feature/25-add-data-retrieve-module' of https://github.…
HC-kang Nov 7, 2024
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
23 changes: 23 additions & 0 deletions src/api/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Grade } from "../type";
import type { Config } from "./type";

export const CONFIG: Config = {
study: {
organization: "DaleStudy",
repository: "leetcode-study",
branchName: "main",
teamPrefix: "leetcode",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 거는 바뀔 가능성이 거의 0%라 설정으로 뽑지 않았으면 합니다. 설사 바뀔 일이 생기더라도 쓰이는 곳이 딱 한 군데라서 아주 쉽게 코드 수정을 할 수 있을 것 같아요.

totalProblemCount: 75,
gradeThresholds: [
["BIG_TREE", 70],
["SMALL_TREE", 60],
["SPROUT", 50],
["SEED", 0],
] as [Grade, number][],
},
gitHub: {
baseUrl: "https://api.github.com",
mediaType: "application/vnd.github+json",
token: process.env.GITHUB_TOKEN ?? "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

브라우저 환경에서는 processundefined일텐데 토큰을 어떻게 설정하실 생각이신가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분이 계속 고민입니다
백엔드가 없는 상태에서 키를 노출시키지 않는것은 사실상 불가능한 게 아닌가 싶어요.

지금 그나마 생각나는 방법은

  1. 사용하지 않는 계정을 생성해서 최소 권한만 부여하고,
  2. 인코딩이나 난독화로 최대한 숨기는 방법이 최선일것 같습니다.

oauth 등의 방법도 팀원이 아니라면 팀원 목록을 볼 수 없는 등 문제가 있어서 결국 팀에 속한 계정의 토큰이 필요할것 같습니다.

그게 아니라면 팀원 목록을 관리할 외부 소스를 두는것도 방법일수 있을 것 같습니다

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HC-kang #14 에서 키의 노출은 불가피한 걸로 이미 얘기가 된 것으로 기억하고 있습니다.

저는 단순히 process가 브라우저에 환경에서는 undefined일텐데 어쩌나 하는 걱정이 있어서 질문을 드렸던 것입니다.

},
} as const;
21 changes: 21 additions & 0 deletions src/api/config/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Grade } from "../type";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { Grade } from "../type";
import type { Grade } from "../type";


export type StudyConfig = {
organization: string;
repository: string;
branchName: string;
teamPrefix: string;
totalProblemCount: number;
gradeThresholds: [Grade, number][];
};

export type GitHubConfig = {
baseUrl: string;
mediaType: string;
token: string;
};

export type Config = {
study: StudyConfig;
gitHub: GitHubConfig;
};
9 changes: 9 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { CONFIG } from "./config";
import { createStoreService } from "./services/store/storeService";

export const leaderBoardStore = await createStoreService(CONFIG);

console.log(await leaderBoardStore.getData());
console.log(await leaderBoardStore.getMemberById("hc"));
console.log(await leaderBoardStore.getMemberByCohort(1));
console.log(await leaderBoardStore.getMemberByGrade("SEED"));
DaleSeo marked this conversation as resolved.
Show resolved Hide resolved
98 changes: 98 additions & 0 deletions src/api/infra/gitHub/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import type { GitHubTeam, GitHubMember, GitHubTree } from "./types";

export const mockGitHubTeams: GitHubTeam[] = [
{
name: "leetcode01",
id: 1,
node_id: "T",
slug: "leetcode01",
description: "리트코드 스터디",
privacy: "closed",
notification_setting: "notifications_enabled",
url: "some-url",
html_url: "some-url",
members_url: "members-url",
repositories_url: "repositories-url",
permission: "pull",
parent: null,
},
{
name: "leetcode02",
id: 2,
node_id: "D",
slug: "leetcode",
description: "리트코드 스터디",
privacy: "closed",
notification_setting: "notifications_enabled",
url: "some-url",
html_url: "some-url",
members_url: "members-url",
repositories_url: "repositories-url",
permission: "pull",
parent: null,
},
];

export const mockGitHubMembers: GitHubMember[] = [
{
login: "D",
id: 1,
node_id: "M",
avatar_url: "avatar-url",
gravatar_id: "",
url: "some-url",
html_url: "some-url",
followers_url: "some-url",
following_url: "some-url",
gists_url: "some-url",
starred_url: "some-url",
subscriptions_url: "some-url",
organizations_url: "some-url",
repos_url: "some-url",
events_url: "some-url",
received_events_url: "some-url",
type: "User",
user_view_type: "public",
site_admin: false,
},
{
login: "S",
id: 2,
node_id: "E",
avatar_url: "avatar-url",
gravatar_id: "",
url: "some-url",
html_url: "some-url",
followers_url: "some-url",
following_url: "some-url",
gists_url: "some-url",
starred_url: "some-url",
subscriptions_url: "some-url",
organizations_url: "some-url",
repos_url: "some-url",
events_url: "some-url",
received_events_url: "some-url",
type: "User",
user_view_type: "public",
site_admin: false,
},
];

export const mockGitHubTree: GitHubTree[] = [
{
path: "best-time-to-buy-and-sell-stock/test.java",
type: "blob",
mode: "100644",
sha: "1",
size: 0,
url: "some-url",
},
{
path: "best-time-to-buy-and-sell-stock/test2.java",
type: "blob",
mode: "100644",
sha: "2",
size: 0,
url: "some-url",
},
];
122 changes: 122 additions & 0 deletions src/api/infra/gitHub/gitHubClient.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { test, expect, beforeEach, vi } from "vitest";
import { createGitHubClient } from "./gitHubClient";
import { CONFIG } from "../../config";
import { mockGitHubTeams, mockGitHubMembers, mockGitHubTree } from "./fixtures";

const mockConfig = {
...CONFIG.gitHub,
token: "test-token",
};

const mockFetch = vi.fn();
global.fetch = mockFetch;

beforeEach(() => {
mockFetch.mockClear();
});

test("getTeamNames should fetch and return team names", async () => {
// Arrange
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockGitHubTeams),
});
const client = createGitHubClient(mockConfig);
const expectedUrl = `${mockConfig.baseUrl}/orgs/test-org/teams`;
const expectedHeaders = {
Accept: mockConfig.mediaType,
Authorization: `token ${mockConfig.token}`,
};

// Act
const result = await client.getTeamNames("test-org");

// Assert
expect(mockFetch).toHaveBeenCalledWith(expectedUrl, {
headers: expectedHeaders,
});
expect(result).toEqual(["leetcode01", "leetcode02"]);
});

test("getTeamNames should throw error when fetch fails", async () => {
// Arrange
mockFetch.mockResolvedValue({
ok: false,
status: 404,
statusText: "Not Found",
});
const client = createGitHubClient(mockConfig);

// Act & Assert
await expect(client.getTeamNames("test-org")).rejects.toThrow(
"Failed to fetch url",
);
});

test("getTeamMembers should fetch and return team members", async () => {
// Arrange
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockGitHubMembers),
});
const client = createGitHubClient(mockConfig);
const expectedUrl = `${mockConfig.baseUrl}/orgs/test-org/teams/test-team/members`;
const expectedHeaders = {
Accept: mockConfig.mediaType,
Authorization: `token ${mockConfig.token}`,
};

// Act
const result = await client.getTeamMembers("test-org", "test-team");

// Assert
expect(mockFetch).toHaveBeenCalledWith(expectedUrl, {
headers: expectedHeaders,
});
expect(result).toEqual(mockGitHubMembers);
});

test("getDirectoryTree should fetch and return directory tree", async () => {
// Arrange
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ tree: mockGitHubTree }),
});
const client = createGitHubClient(mockConfig);
const expectedUrl = `${mockConfig.baseUrl}/repos/test-owner/test-repo/git/trees/main?recursive=1`;
const expectedHeaders = {
Accept: mockConfig.mediaType,
Authorization: `token ${mockConfig.token}`,
};

// Act
const result = await client.getDirectoryTree(
"test-owner",
"test-repo",
"main",
);

// Assert
expect(mockFetch).toHaveBeenCalledWith(expectedUrl, {
headers: expectedHeaders,
});
expect(result).toEqual(mockGitHubTree);
});

test("error should include detailed information", async () => {
// Arrange
const status = 403;
const statusText = "Forbidden";
mockFetch.mockResolvedValue({
ok: false,
status,
statusText,
});
const client = createGitHubClient(mockConfig);
const expectedErrorMessage = `Failed to fetch url: ${mockConfig.baseUrl}/orgs/test-org/teams, status: ${status}, statusText: ${statusText}`;

// Act & Assert
await expect(client.getTeamNames("test-org")).rejects.toThrow(
expectedErrorMessage,
);
});
54 changes: 54 additions & 0 deletions src/api/infra/gitHub/gitHubClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { GitHubConfig } from "../../config/type";
import type {
GitHubMember,
GitHubTeam,
GitHubTree,
GitHubTreeResponse,
} from "./types";

export const createGitHubClient = (config: GitHubConfig) => {
const request = async (url: string, token: string): Promise<unknown> => {
const response = await fetch(url, {
headers: {
Accept: config.mediaType,
Authorization: `token ${token}`,
},
});

if (!response.ok) {
throw new Error(
`Failed to fetch url: ${url}, status: ${response.status}, statusText: ${response.statusText}`,
);
}

return response.json();
};

return {
getTeamNames: async (organization: string): Promise<string[]> =>
request(
`${config.baseUrl}/orgs/${organization}/teams`,
config.token,
).then((response) => (response as GitHubTeam[]).map((team) => team.name)),

getTeamMembers: async (
organization: string,
teamName: string,
): Promise<GitHubMember[]> =>
request(
`${config.baseUrl}/orgs/${organization}/teams/${teamName}/members`,
config.token,
).then((response) => response as GitHubMember[]),

getDirectoryTree: async (
owner: string,
repo: string,
treeSha: string,
recursive = 1,
): Promise<GitHubTree[]> =>
request(
`${config.baseUrl}/repos/${owner}/${repo}/git/trees/${treeSha}?recursive=${recursive}`,
config.token,
).then((response) => (response as GitHubTreeResponse).tree),
};
};
52 changes: 52 additions & 0 deletions src/api/infra/gitHub/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
export type GitHubTeam = {
name: string;
id: number;
node_id: string;
slug: string;
description: string;
privacy: string;
notification_setting: string;
url: string;
html_url: string;
members_url: string;
repositories_url: string;
permission: string;
parent: null;
};

export type GitHubMember = {
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;
user_view_type: string;
site_admin: boolean;
};

export type GitHubTreeResponse = {
sha: string;
url: string;
tree: GitHubTree[];
};

export type GitHubTree = {
path: string;
mode: string;
type: string;
size: number;
sha: string;
url: string;
};
Loading