Add experience endpoint & data
This commit is contained in:
parent
d5132520cb
commit
b3812c2b40
6 changed files with 191 additions and 6 deletions
|
|
@ -2,23 +2,27 @@ import { Test, TestingModule } from "@nestjs/testing";
|
|||
import { AppController } from "@/app.controller";
|
||||
import { AppService } from "@/app.service";
|
||||
import { SkillsService } from "@/skills/skills.service";
|
||||
import { ExperiencesService } from "@/experiences/experiences.service";
|
||||
import { SkillDto } from "@/skills/skills.types";
|
||||
import { ExperienceDto, ExperienceType } from "@/experiences/experiences.types";
|
||||
|
||||
describe("AppController", () => {
|
||||
let appController: AppController;
|
||||
let appService: AppService;
|
||||
let skillsService: SkillsService;
|
||||
let experiencesService: ExperiencesService;
|
||||
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService, SkillsService],
|
||||
providers: [AppService, SkillsService, ExperiencesService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
appService = app.get<AppService>(AppService);
|
||||
skillsService = app.get<SkillsService>(SkillsService);
|
||||
experiencesService = app.get<ExperiencesService>(ExperiencesService);
|
||||
});
|
||||
|
||||
describe("root", () => {
|
||||
|
|
@ -46,5 +50,22 @@ describe("AppController", () => {
|
|||
expect(skillsService.getMany).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getExperience", () => {
|
||||
it("Should return an Array of ExperienceDtos", () => {
|
||||
const result: ExperienceDto[] = ExperienceDto.asDto([{
|
||||
name: "experienceName",
|
||||
city: "experienceCity",
|
||||
jobTitle: "experienceJobTitle",
|
||||
startDate: new Date(),
|
||||
endDate: new Date(),
|
||||
description: "experienceDescription",
|
||||
skills: []
|
||||
}]);
|
||||
|
||||
jest.spyOn(experiencesService, "getMany").mockImplementation(() => result)
|
||||
expect(appController.getExperiences()).toBe(result);
|
||||
expect(experiencesService.getMany).toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ import { ApiExcludeEndpoint, ApiExtraModels, ApiOkResponse, ApiTags, getSchemaPa
|
|||
import { SkillsService } from "@/skills/skills.service";
|
||||
import { ExperiencesService } from "@/experiences/experiences.service";
|
||||
import { SkillDto } from "@/skills/skills.types";
|
||||
import { ExperienceDto } from "@/experiences/experiences.types";
|
||||
|
||||
@Controller()
|
||||
@ApiExtraModels(SkillDto)
|
||||
@ApiExtraModels(SkillDto, ExperienceDto)
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService, private readonly skillsService: SkillsService, private readonly experiencesService: ExperiencesService) {
|
||||
}
|
||||
|
|
@ -30,4 +31,18 @@ export class AppController {
|
|||
getSkills(): ReadonlyArray<SkillDto> {
|
||||
return this.skillsService.getMany();
|
||||
}
|
||||
|
||||
@Get("experiences")
|
||||
@ApiTags("Experience")
|
||||
@ApiOkResponse({
|
||||
description: "Returns a list of previous work experiences",
|
||||
schema: {
|
||||
items: {
|
||||
$ref: getSchemaPath(ExperienceDto),
|
||||
},
|
||||
},
|
||||
})
|
||||
getExperiences(): ReadonlyArray<ExperienceDto> {
|
||||
return this.experiencesService.getMany();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ExperiencesService } from './experiences.service';
|
||||
import { SkillsService } from "@/skills/skills.service";
|
||||
|
||||
describe('ExperiencesService', () => {
|
||||
let service: ExperiencesService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [ExperiencesService],
|
||||
providers: [ExperiencesService, SkillsService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<ExperiencesService>(ExperiencesService);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,35 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { ExperienceDto, ExperienceType } from "@/experiences/experiences.types";
|
||||
import { SkillsService } from "@/skills/skills.service";
|
||||
import { experiences } from "@/experiences/experiences";
|
||||
import { SkillDto } from "@/skills/skills.types";
|
||||
|
||||
@Injectable()
|
||||
export class ExperiencesService {
|
||||
private readonly
|
||||
constructor() {
|
||||
private readonly experiences: ReadonlyArray<ExperienceDto>;
|
||||
|
||||
constructor(
|
||||
private readonly skillsService: SkillsService
|
||||
) {
|
||||
this.experiences = ExperienceDto.asDto(this.linkSkills(experiences))
|
||||
.sort((experienceA, experienceB) => experienceA.startDate > experienceB.startDate ? 1 : -1);
|
||||
}
|
||||
|
||||
getMany(filter?: Partial<Omit<ExperienceType, "startDate" | "endDate" | "skills">>) {
|
||||
const filtersValues = Object.entries(filter ?? {}).map(([key, filterValue]) => ([key, new RegExp(filterValue, "i")])) as [keyof Omit<ExperienceType, "startDate" | "endDate" | "skills">, RegExp][];
|
||||
if (!filter || filtersValues.length === 0) {
|
||||
return this.experiences;
|
||||
}
|
||||
|
||||
return this.experiences.filter((experience) => filtersValues.every(([key, filterValue]) => filterValue.test(experience[key])));
|
||||
}
|
||||
|
||||
private linkSkills(experiences: ExperienceType[]): Array<ExperienceType & { skills: ReadonlyArray<SkillDto> }> {
|
||||
return experiences.map((experience) => {
|
||||
return {
|
||||
...experience,
|
||||
skills: experience.skills.map(partialSkill => this.skillsService.getMany(partialSkill)).flat()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
71
cv/src/experiences/experiences.ts
Normal file
71
cv/src/experiences/experiences.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import { ExperienceType } from "@/experiences/experiences.types";
|
||||
|
||||
export const experiences: ExperienceType[] = [
|
||||
{
|
||||
name: "Saysimple / Just Internet Group",
|
||||
city: "Haarlem",
|
||||
url: "https://saysimple.com/",
|
||||
jobTitle: "Senior Developer / DevOps",
|
||||
startDate: new Date(2018, 9, 1),
|
||||
endDate: null,
|
||||
description: `I started at Just Internet Group in 2018 working on Cocoon, a SaaS digital Asset Management (DAM) system. Here I implemented ElasticSearch & Kibana to keep track of assets uploaded and downloaded.
|
||||
Later on I switched to Saysimple, to start building our brand new Customer Communication Platform. For Saysimple I was responsible for creating and maintaining our CI/CD pipelines, the EKS cluster and our HAProxy loadbalancers.
|
||||
During my time
|
||||
`,
|
||||
skills: [
|
||||
{
|
||||
category: "AWS|Containerization|DevOps|Business Intelligence|Team Management"
|
||||
},
|
||||
{
|
||||
name: "NodeJs|Git"
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Blackorange",
|
||||
city: "Amsterdam",
|
||||
url: "http://blackorange.nl/",
|
||||
jobTitle: "Junior Developer / System Administrator",
|
||||
startDate: new Date(2018, 9, 1),
|
||||
endDate: new Date(2018, 8, 30),
|
||||
description: "",
|
||||
skills: [
|
||||
{
|
||||
category: "AWS|Containerization|DevOps"
|
||||
},
|
||||
{
|
||||
name: "NodeJs|Git|Server"
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Werring Webdevelopment",
|
||||
city: "Middenbeemster",
|
||||
jobTitle: "ZZP",
|
||||
startDate: new Date(2018, 9, 1),
|
||||
endDate: new Date(2018, 8, 30),
|
||||
description: "",
|
||||
skills: [
|
||||
{
|
||||
name: "PHP|Webhosting"
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sv. Ingenium",
|
||||
city: "Utrecht",
|
||||
url: "http://ingeniumcabobianci.nl/",
|
||||
jobTitle: "Penningmeester",
|
||||
startDate: new Date(2018, 9, 1),
|
||||
endDate: new Date(2018, 8, 30),
|
||||
description: "",
|
||||
skills: [
|
||||
{
|
||||
name: "Finances"
|
||||
},
|
||||
{
|
||||
category: "Organization"
|
||||
},
|
||||
],
|
||||
},
|
||||
] satisfies ExperienceType[];
|
||||
52
cv/src/experiences/experiences.types.ts
Normal file
52
cv/src/experiences/experiences.types.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import { ApiProperty, getSchemaPath } from "@nestjs/swagger";
|
||||
import { DtoClass } from "@/common/types";
|
||||
import { SkillDto } from "@/skills/skills.types";
|
||||
|
||||
export type ExperienceType = {
|
||||
name: string;
|
||||
city: string;
|
||||
url?: string;
|
||||
jobTitle: string;
|
||||
description: string;
|
||||
startDate: Date;
|
||||
endDate: Date | null;
|
||||
skills: Partial<SkillDto>[];
|
||||
}
|
||||
|
||||
export class ExperienceDto extends DtoClass<ExperienceType, ExperienceDto>() implements ExperienceType {
|
||||
@ApiProperty()
|
||||
readonly name: string;
|
||||
@ApiProperty()
|
||||
readonly city: string;
|
||||
@ApiProperty()
|
||||
readonly url?: string
|
||||
@ApiProperty()
|
||||
readonly jobTitle: string;
|
||||
@ApiProperty()
|
||||
readonly description: string;
|
||||
@ApiProperty()
|
||||
readonly startDate: Date;
|
||||
@ApiProperty()
|
||||
readonly endDate: Date | null;
|
||||
@ApiProperty({
|
||||
type: [SkillDto],
|
||||
items: {
|
||||
$ref: getSchemaPath(SkillDto)
|
||||
}
|
||||
})
|
||||
readonly skills: SkillDto[];
|
||||
|
||||
constructor(experience: ExperienceType) {
|
||||
super(experience);
|
||||
Object.assign(this, {
|
||||
name: experience.name,
|
||||
city: experience.city,
|
||||
url: experience.url,
|
||||
jobTitle: experience.jobTitle,
|
||||
description: experience.description,
|
||||
startDate: experience.startDate,
|
||||
endDate: experience.endDate,
|
||||
skills: experience.skills,
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue