From 344b59432c3fedc990653cbe7850dffb73faa919 Mon Sep 17 00:00:00 2001 From: IzN432 Date: Mon, 10 Feb 2025 12:53:58 +0800 Subject: [PATCH 1/5] Add GithubRestIssue to handle Rest responses --- .../core/models/github/github-issue.model.ts | 8 ++++++ .../core/models/github/github-rest-issue.ts | 26 +++++++++++++++++++ src/app/core/services/github.service.ts | 15 ++++++----- 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 src/app/core/models/github/github-rest-issue.ts diff --git a/src/app/core/models/github/github-issue.model.ts b/src/app/core/models/github/github-issue.model.ts index c2fec9485..04f6d90f3 100644 --- a/src/app/core/models/github/github-issue.model.ts +++ b/src/app/core/models/github/github-issue.model.ts @@ -1,6 +1,7 @@ import { IssueState } from '../../../../../graphql/graphql-types'; import { GithubComment } from './github-comment.model'; import { GithubLabel } from './github-label.model'; +import { GithubRestIssue } from './github-rest-issue'; export class GithubIssue { id: string; // Github's backend's id @@ -67,4 +68,11 @@ export class GithubIssue { findTeamId(): string { return `${this.findLabel('team')}.${this.findLabel('tutorial')}`; } + + static fromRestGithubIssue(restGithubIssue: GithubRestIssue): GithubIssue { + return new GithubIssue({ + ...restGithubIssue, + state: restGithubIssue.state.toUpperCase() + }); + } } diff --git a/src/app/core/models/github/github-rest-issue.ts b/src/app/core/models/github/github-rest-issue.ts new file mode 100644 index 000000000..103b81d1e --- /dev/null +++ b/src/app/core/models/github/github-rest-issue.ts @@ -0,0 +1,26 @@ +import { GithubComment } from './github-comment.model'; +import { GithubLabel } from './github-label.model'; + +export type GithubRestIssue = { + id: string; // Github's backend's id + number: number; // Issue's display id + assignees: Array<{ + id: number; + login: string; + url: string; + }>; + body: string; + created_at: string; + labels: Array; + state: 'open' | 'closed'; + title: string; + updated_at: string; + url: string; + user: { + // Author of the issue + login: string; + avatar_url: string; + url: string; + }; + comments: Array; +}; diff --git a/src/app/core/services/github.service.ts b/src/app/core/services/github.service.ts index 579f98d0b..451921ff8 100644 --- a/src/app/core/services/github.service.ts +++ b/src/app/core/services/github.service.ts @@ -32,6 +32,7 @@ import { GithubRelease } from '../models/github/github.release'; import { SessionData } from '../models/session.model'; import { ERRORCODE_NOT_FOUND, ErrorHandlingService } from './error-handling.service'; import { LoggingService } from './logging.service'; +import { GithubRestIssue } from '../models/github/github-rest-issue'; const { Octokit } = require('@octokit/rest'); const CATCHER_ORG = 'CATcher-org'; @@ -362,25 +363,25 @@ export class GithubService { closeIssue(id: number): Observable { return from(octokit.issues.update({ owner: ORG_NAME, repo: REPO, issue_number: id, state: 'closed' })).pipe( - map((response: GithubResponse) => { + map((response: GithubResponse) => { this.issuesLastModifiedManager.set(id, response.headers['last-modified']); - return new GithubIssue(response.data); + return GithubIssue.fromRestGithubIssue(response.data); }) ); } reopenIssue(id: number): Observable { return from(octokit.issues.update({ owner: ORG_NAME, repo: REPO, issue_number: id, state: 'open' })).pipe( - map((response: GithubResponse) => { + map((response: GithubResponse) => { this.issuesLastModifiedManager.set(id, response.headers['last-modified']); - return new GithubIssue(response.data); + return GithubIssue.fromRestGithubIssue(response.data); }) ); } createIssue(title: string, description: string, labels: string[]): Observable { return from(octokit.issues.create({ owner: ORG_NAME, repo: REPO, title: title, body: description, labels: labels })).pipe( - map((response: GithubResponse) => new GithubIssue(response.data)) + map((response: GithubResponse) => GithubIssue.fromRestGithubIssue(response.data)) ); } @@ -402,9 +403,9 @@ export class GithubService { assignees: assignees }) ).pipe( - map((response: GithubResponse) => { + map((response: GithubResponse) => { this.issuesLastModifiedManager.set(id, response.headers['last-modified']); - return new GithubIssue(response.data); + return GithubIssue.fromRestGithubIssue(response.data); }), catchError((err) => throwError(err)) ); From 2fd6d6c1b91c437e86a77f14adf536a591c1f9d0 Mon Sep 17 00:00:00 2001 From: IzN432 Date: Mon, 10 Feb 2025 12:58:14 +0800 Subject: [PATCH 2/5] Fix lint --- src/app/core/models/github/github-issue.model.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/core/models/github/github-issue.model.ts b/src/app/core/models/github/github-issue.model.ts index 04f6d90f3..62fd8110b 100644 --- a/src/app/core/models/github/github-issue.model.ts +++ b/src/app/core/models/github/github-issue.model.ts @@ -26,6 +26,13 @@ export class GithubIssue { }; comments: Array; + static fromRestGithubIssue(restGithubIssue: GithubRestIssue): GithubIssue { + return new GithubIssue({ + ...restGithubIssue, + state: restGithubIssue.state.toUpperCase() + }); + } + constructor(githubIssue: {}) { Object.assign(this, githubIssue); this.labels = []; @@ -68,11 +75,4 @@ export class GithubIssue { findTeamId(): string { return `${this.findLabel('team')}.${this.findLabel('tutorial')}`; } - - static fromRestGithubIssue(restGithubIssue: GithubRestIssue): GithubIssue { - return new GithubIssue({ - ...restGithubIssue, - state: restGithubIssue.state.toUpperCase() - }); - } } From 04dab071521c2789c1f2a795e6475403c7470a83 Mon Sep 17 00:00:00 2001 From: IzN432 Date: Mon, 10 Feb 2025 13:50:48 +0800 Subject: [PATCH 3/5] Update to use RestGithubIssueState --- src/app/core/models/github/github-rest-issue.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/core/models/github/github-rest-issue.ts b/src/app/core/models/github/github-rest-issue.ts index 103b81d1e..e5b82eb44 100644 --- a/src/app/core/models/github/github-rest-issue.ts +++ b/src/app/core/models/github/github-rest-issue.ts @@ -1,4 +1,5 @@ import { GithubComment } from './github-comment.model'; +import { RestGithubIssueState } from './github-issue-filter.model'; import { GithubLabel } from './github-label.model'; export type GithubRestIssue = { @@ -12,7 +13,7 @@ export type GithubRestIssue = { body: string; created_at: string; labels: Array; - state: 'open' | 'closed'; + state: RestGithubIssueState; title: string; updated_at: string; url: string; From cfb9e87b6f944dc63e9654fdd4f254440e5bcd90 Mon Sep 17 00:00:00 2001 From: IzN432 Date: Mon, 10 Feb 2025 13:52:32 +0800 Subject: [PATCH 4/5] Move GithubRestIssueState to github-rest-issue.ts --- src/app/core/models/github/github-issue-filter.model.ts | 2 +- src/app/core/models/github/github-rest-issue.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/core/models/github/github-issue-filter.model.ts b/src/app/core/models/github/github-issue-filter.model.ts index a55b7ec1d..e45f3c105 100644 --- a/src/app/core/models/github/github-issue-filter.model.ts +++ b/src/app/core/models/github/github-issue-filter.model.ts @@ -1,6 +1,6 @@ import { IssueFilters, IssueState } from '../../../../../graphql/graphql-types'; +import { RestGithubIssueState } from './github-rest-issue'; -export type RestGithubIssueState = 'open' | 'closed' | 'all'; export type RestGithubSortBy = 'created' | 'updated' | 'comments'; export type RestGithubSortDir = 'asc' | 'desc'; diff --git a/src/app/core/models/github/github-rest-issue.ts b/src/app/core/models/github/github-rest-issue.ts index e5b82eb44..19ecdc05e 100644 --- a/src/app/core/models/github/github-rest-issue.ts +++ b/src/app/core/models/github/github-rest-issue.ts @@ -1,7 +1,8 @@ import { GithubComment } from './github-comment.model'; -import { RestGithubIssueState } from './github-issue-filter.model'; import { GithubLabel } from './github-label.model'; +export type RestGithubIssueState = 'open' | 'closed' | 'all'; + export type GithubRestIssue = { id: string; // Github's backend's id number: number; // Issue's display id From f1cb2438675344fb2b757ce7b3fbbaa2d85f51d1 Mon Sep 17 00:00:00 2001 From: IzN432 Date: Mon, 10 Feb 2025 14:35:55 +0800 Subject: [PATCH 5/5] Replace more instances of GithubIssue --- .../cache-manager/issues-cache-manager.model.ts | 8 ++++---- src/app/core/services/github.service.ts | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app/core/models/github/cache-manager/issues-cache-manager.model.ts b/src/app/core/models/github/cache-manager/issues-cache-manager.model.ts index f243db652..57ccffb0c 100644 --- a/src/app/core/models/github/cache-manager/issues-cache-manager.model.ts +++ b/src/app/core/models/github/cache-manager/issues-cache-manager.model.ts @@ -1,5 +1,5 @@ -import { GithubIssue } from '../github-issue.model'; import { GithubResponse } from '../github-response.model'; +import { GithubRestIssue } from '../github-rest-issue'; /** * A model that is used to manage the cache of multiple list of issues paginated by pages. @@ -8,7 +8,7 @@ import { GithubResponse } from '../github-response.model'; export class IssuesCacheManager { // An array of cache github responses containing the array of GithubIssue as its data // The index in this array represents (page number - 1) - private issuesCache: GithubResponse[]; + private issuesCache: GithubResponse[]; constructor() { this.issuesCache = []; @@ -23,11 +23,11 @@ export class IssuesCacheManager { return latestEtag; } - get(pageNumber: number): GithubResponse { + get(pageNumber: number): GithubResponse { return this.issuesCache[pageNumber - 1]; } - set(pageNumber: number, response: GithubResponse): void { + set(pageNumber: number, response: GithubResponse): void { response.isCached = true; this.issuesCache[pageNumber - 1] = response; } diff --git a/src/app/core/services/github.service.ts b/src/app/core/services/github.service.ts index 451921ff8..e3bc23efa 100644 --- a/src/app/core/services/github.service.ts +++ b/src/app/core/services/github.service.ts @@ -154,20 +154,20 @@ export class GithubService { * @returns Observable that returns true if there are pages that do not exist in the cache model. */ private toFetchIssues(filter: RestGithubIssueFilter): Observable { - let responseInFirstPage: GithubResponse; + let responseInFirstPage: GithubResponse; return this.getIssuesAPICall(filter, 1).pipe( - map((response: GithubResponse) => { + map((response: GithubResponse) => { responseInFirstPage = response; return getNumberOfPages(response); }), mergeMap((numOfPages: number) => { - const apiCalls: Observable>[] = []; + const apiCalls: Observable>[] = []; for (let i = 2; i <= numOfPages; i++) { apiCalls.push(this.getIssuesAPICall(filter, i)); } return apiCalls.length === 0 ? of([]) : forkJoin(apiCalls); }), - map((resultArray: GithubResponse[]) => { + map((resultArray: GithubResponse[]) => { const responses = [responseInFirstPage, ...resultArray]; const isCached = responses.reduce((result, response) => result && response.isCached, true); responses.forEach((resp, index) => this.issuesCacheManager.set(index + 1, resp)); @@ -321,7 +321,7 @@ export class GithubService { headers: { 'If-Modified-Since': this.issuesLastModifiedManager.get(id) } }) ).pipe( - map((response: GithubResponse) => { + map((response: GithubResponse) => { this.issuesLastModifiedManager.set(id, response.headers['last-modified']); return true; }), @@ -525,8 +525,8 @@ export class GithubService { * @param pageNumber - The page to be fetched * @returns An observable representing the response containing a single page of filtered issues */ - private getIssuesAPICall(filter: RestGithubIssueFilter, pageNumber: number): Observable> { - const apiCall: Promise> = octokit.issues.listForRepo({ + private getIssuesAPICall(filter: RestGithubIssueFilter, pageNumber: number): Observable> { + const apiCall: Promise> = octokit.issues.listForRepo({ ...filter, owner: ORG_NAME, repo: REPO,