-
Notifications
You must be signed in to change notification settings - Fork 0
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 contributors page gf-250 #334
Changes from 30 commits
f5d9de6
7461829
4d0e9b8
2289706
22e6216
659e7f5
02234ce
a653cba
e2ea3e5
15cf55d
9d0ef9e
412a653
aa352f5
89c6bc0
7f20e8c
d00ce32
012f5b4
8784427
dbaa681
bed8389
cca9651
98f4be6
77bf018
2eb91d1
e3fd7cb
1bd48f1
1362f3e
55ade8b
8cd5d9f
702150d
05436d8
35c8304
8fab5d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { APIPath } from "~/libs/enums/enums.js"; | ||
import { | ||
type APIHandlerResponse, | ||
BaseController, | ||
} from "~/libs/modules/controller/controller.js"; | ||
import { HTTPCode } from "~/libs/modules/http/http.js"; | ||
import { type Logger } from "~/libs/modules/logger/logger.js"; | ||
|
||
import { type ContributorService } from "./contributor.service.js"; | ||
import { ContributorsApiPath } from "./libs/enums/enums.js"; | ||
|
||
/** | ||
* @swagger | ||
* components: | ||
* schemas: | ||
* Contributor: | ||
* type: object | ||
* properties: | ||
* id: | ||
* type: number | ||
* minimum: 1 | ||
* name: | ||
* type: string | ||
* gitEmails: | ||
* type: array | ||
* items: | ||
* type: object | ||
* properties: | ||
* id: | ||
* type: number | ||
* minimum: 1 | ||
* email: | ||
* type: string | ||
* projects: | ||
* type: array | ||
* items: | ||
* type: object | ||
* properties: | ||
* id: | ||
* type: number | ||
* minimum: 1 | ||
* name: | ||
* type: string | ||
*/ | ||
class ContributorController extends BaseController { | ||
private contributorService: ContributorService; | ||
|
||
public constructor(logger: Logger, contributorService: ContributorService) { | ||
super(logger, APIPath.CONTRIBUTORS); | ||
|
||
this.contributorService = contributorService; | ||
|
||
this.addRoute({ | ||
handler: () => this.findAll(), | ||
method: "GET", | ||
path: ContributorsApiPath.ROOT, | ||
}); | ||
} | ||
|
||
/** | ||
* @swagger | ||
* /contributors: | ||
* get: | ||
* description: Returns an array of contributors | ||
* responses: | ||
* 200: | ||
* description: Successful operation | ||
* content: | ||
* application/json: | ||
* schema: | ||
* type: object | ||
* properties: | ||
* items: | ||
* type: array | ||
* items: | ||
* $ref: "#/components/schemas/Contributor" | ||
*/ | ||
private async findAll(): Promise<APIHandlerResponse> { | ||
return { | ||
payload: await this.contributorService.findAll(), | ||
status: HTTPCode.OK, | ||
}; | ||
} | ||
} | ||
|
||
export { ContributorController }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
import { raw } from "objection"; | ||
|
||
import { type Repository } from "~/libs/types/types.js"; | ||
|
||
import { ContributorEntity } from "./contributor.entity.js"; | ||
|
@@ -15,35 +17,68 @@ class ContributorRepository implements Repository { | |
|
||
const contributor = await this.contributorModel | ||
.query() | ||
.insert({ | ||
name, | ||
}) | ||
.insert({ name }) | ||
.execute(); | ||
|
||
return ContributorEntity.initialize(contributor); | ||
return ContributorEntity.initialize({ ...contributor, projects: [] }); | ||
} | ||
|
||
public delete(): ReturnType<Repository["delete"]> { | ||
return Promise.resolve(true); | ||
} | ||
|
||
public async find(id: number): Promise<ContributorEntity | null> { | ||
const item = await this.contributorModel.query().findById(id).execute(); | ||
const contributor = await this.contributorModel | ||
.query() | ||
.findById(id) | ||
.withGraphFetched("gitEmails"); | ||
GvoFor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return item ? ContributorEntity.initialize(item) : null; | ||
if (!contributor) { | ||
return null; | ||
} | ||
|
||
return ContributorEntity.initialize({ ...contributor, projects: [] }); | ||
} | ||
|
||
public findAll(): ReturnType<Repository["findAll"]> { | ||
return Promise.resolve({ items: [] }); | ||
public async findAll(): Promise<{ items: ContributorEntity[] }> { | ||
const contributorsWithProjectsAndEmails = await this.contributorModel | ||
.query() | ||
.select("contributors.*") | ||
.select( | ||
raw( | ||
"COALESCE(ARRAY_AGG(DISTINCT jsonb_build_object('id', projects.id, 'name', projects.name)) FILTER (WHERE projects.id IS NOT NULL), '{}') AS projects", | ||
), | ||
) | ||
.select( | ||
raw( | ||
"COALESCE(ARRAY_AGG(DISTINCT jsonb_build_object('id', git_emails.id, 'email', git_emails.email)) FILTER (WHERE git_emails.id IS NOT NULL), '{}') AS git_emails", | ||
), | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can join git emails the usual way, with relation mapping, because we will probably need this in another place |
||
.leftJoin("git_emails", "contributors.id", "git_emails.contributor_id") | ||
.leftJoin("activity_logs", "git_emails.id", "activity_logs.git_email_id") | ||
.leftJoin("projects", "activity_logs.project_id", "projects.id") | ||
.groupBy("contributors.id"); | ||
|
||
return { | ||
items: contributorsWithProjectsAndEmails.map((contributor) => { | ||
return ContributorEntity.initialize({ | ||
...contributor, | ||
}); | ||
}), | ||
}; | ||
} | ||
|
||
public async findByName(name: string): Promise<ContributorEntity | null> { | ||
const item = await this.contributorModel | ||
const contributor = await this.contributorModel | ||
.query() | ||
.findOne({ name }) | ||
.execute(); | ||
.withGraphFetched("gitEmails"); | ||
|
||
if (!contributor) { | ||
return null; | ||
} | ||
|
||
return item ? ContributorEntity.initialize(item) : null; | ||
return ContributorEntity.initialize({ ...contributor, projects: [] }); | ||
} | ||
|
||
public update(): ReturnType<Repository["update"]> { | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -2,19 +2,26 @@ import { ExceptionMessage } from "~/libs/enums/enums.js"; | |||
import { HTTPCode } from "~/libs/modules/http/http.js"; | ||||
import { type Service } from "~/libs/types/types.js"; | ||||
|
||||
import { type ProjectService } from "../projects/project.service.js"; | ||||
import { ContributorEntity } from "./contributor.entity.js"; | ||||
import { type ContributorRepository } from "./contributor.repository.js"; | ||||
import { ContributorError } from "./libs/exceptions/exceptions.js"; | ||||
import { | ||||
type ContributorCreateRequestDto, | ||||
type ContributorGetAllItemResponseDto, | ||||
type ContributorGetAllResponseDto, | ||||
} from "./libs/types/types.js"; | ||||
|
||||
class ContributorService implements Service { | ||||
private contributorRepository: ContributorRepository; | ||||
private projectService: ProjectService; | ||||
|
||||
public constructor(contributorRepository: ContributorRepository) { | ||||
public constructor( | ||||
contributorRepository: ContributorRepository, | ||||
projectService: ProjectService, | ||||
) { | ||||
this.contributorRepository = contributorRepository; | ||||
this.projectService = projectService; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like we no longer need this
Suggested change
|
||||
} | ||||
|
||||
public async create( | ||||
|
@@ -48,16 +55,22 @@ class ContributorService implements Service { | |||
return item.toObject(); | ||||
} | ||||
|
||||
public findAll(): ReturnType<Service["findAll"]> { | ||||
return Promise.resolve({ items: [] }); | ||||
public async findAll(): Promise<ContributorGetAllResponseDto> { | ||||
const contributors = await this.contributorRepository.findAll(); | ||||
|
||||
return { items: contributors.items.map((item) => item.toObject()) }; | ||||
} | ||||
|
||||
public async findByName( | ||||
name: string, | ||||
): Promise<ContributorGetAllItemResponseDto | null> { | ||||
const item = await this.contributorRepository.findByName(name); | ||||
|
||||
return item ? item.toObject() : null; | ||||
if (!item) { | ||||
return null; | ||||
} | ||||
|
||||
return item.toObject(); | ||||
} | ||||
|
||||
public update(): ReturnType<Service["update"]> { | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,21 @@ | ||
import { logger } from "~/libs/modules/logger/logger.js"; | ||
|
||
import { projectService } from "../projects/projects.js"; | ||
import { ContributorController } from "./contributor.controller.js"; | ||
import { ContributorModel } from "./contributor.model.js"; | ||
import { ContributorRepository } from "./contributor.repository.js"; | ||
import { ContributorService } from "./contributors.service.js"; | ||
import { ContributorService } from "./contributor.service.js"; | ||
|
||
const contributorRepository = new ContributorRepository(ContributorModel); | ||
const contributorService = new ContributorService(contributorRepository); | ||
const contributorService = new ContributorService( | ||
contributorRepository, | ||
projectService, | ||
); | ||
const contributorController = new ContributorController( | ||
logger, | ||
contributorService, | ||
); | ||
|
||
export { ContributorModel } from "./contributor.model.js"; | ||
export { ContributorRepository } from "./contributor.repository.js"; | ||
export { ContributorService } from "./contributors.service.js"; | ||
export { contributorService }; | ||
export { ContributorService } from "./contributor.service.js"; | ||
export { contributorController, contributorService }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { ContributorsApiPath } from "@git-fit/shared"; |
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.
Can't we leave
return ContributorEntity.initialize(contributor);
?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.
Yeah, now that we have one query for that, we can, I forgot to change it. Thanks!