mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-13 08:13:49 +10:00
feat(client/import): implement import json from reactive resume v2
This commit is contained in:
@ -42,4 +42,15 @@ export class IntegrationsController {
|
||||
|
||||
return this.integrationsService.reactiveResume(userId, file.path);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('reactive-resume-v2')
|
||||
@UseInterceptors(FileInterceptor('file'))
|
||||
reactiveResumeV2(@User('id') userId: number, @UploadedFile() file: Express.Multer.File) {
|
||||
if (!file) {
|
||||
throw new HttpException('You must upload a valid JSON file.', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
return this.integrationsService.reactiveResumeV2(userId, file.path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -616,4 +616,333 @@ export class IntegrationsService {
|
||||
await unlink(path);
|
||||
}
|
||||
}
|
||||
|
||||
async reactiveResumeV2(userId: number, path: string): Promise<ResumeEntity> {
|
||||
try {
|
||||
const jsonResume = JSON.parse(await readFile(path, 'utf8'));
|
||||
|
||||
const resume: Partial<Resume> = cloneDeep(defaultState);
|
||||
|
||||
// Metadata
|
||||
const timestamp = dayjs().format(FILENAME_TIMESTAMP);
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
name: `Imported from Reactive Resume V2 (${timestamp})`,
|
||||
slug: `imported-from-reactive-resume-v2-${timestamp}`,
|
||||
});
|
||||
|
||||
// Basics
|
||||
try {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
basics: {
|
||||
name: get(jsonResume, 'profile.firstName') + ' ' + get(jsonResume, 'profile.lastName'),
|
||||
headline: get(jsonResume, 'profile.subtitle'),
|
||||
photo: {
|
||||
url: get(jsonResume, 'profile.photograph'),
|
||||
},
|
||||
email: get(jsonResume, 'profile.email'),
|
||||
phone: get(jsonResume, 'profile.phone'),
|
||||
website: get(jsonResume, 'profile.website'),
|
||||
summary: get(jsonResume, 'objective'),
|
||||
location: {
|
||||
address: get(jsonResume, 'profile.address.line1'),
|
||||
postalCode: get(jsonResume, 'profile.address.pincode'),
|
||||
city: get(jsonResume, 'profile.address.city'),
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Profiles
|
||||
try {
|
||||
const profiles: any[] = get(jsonResume, 'social.items', []);
|
||||
profiles.forEach((profile) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
basics: {
|
||||
profiles: [
|
||||
...resume.basics.profiles,
|
||||
{
|
||||
id: uuidv4(),
|
||||
url: get(profile, 'url'),
|
||||
network: get(profile, 'network'),
|
||||
username: get(profile, 'username'),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Work
|
||||
try {
|
||||
const work: any[] = get(jsonResume, 'work.items', []);
|
||||
work.forEach((item) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
work: {
|
||||
items: [
|
||||
...get(resume, 'sections.work.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: get(item, 'company'),
|
||||
position: get(item, 'position'),
|
||||
summary: get(item, 'summary'),
|
||||
url: get(item, 'website'),
|
||||
date: {
|
||||
start: dayjs(get(item, 'startDate')).toISOString(),
|
||||
end: dayjs(get(item, 'endDate')).toISOString(),
|
||||
},
|
||||
} as WorkExperience,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Education
|
||||
try {
|
||||
const education: any[] = get(jsonResume, 'education.items', []);
|
||||
education.forEach((item) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
education: {
|
||||
items: [
|
||||
...get(resume, 'sections.education.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
institution: get(item, 'institution'),
|
||||
degree: get(item, 'studyType'),
|
||||
url: get(item, 'url'),
|
||||
score: get(item, 'gpa'),
|
||||
area: get(item, 'field'),
|
||||
summary: get(item, 'summary'),
|
||||
courses: get(item, 'courses', []),
|
||||
date: {
|
||||
start: dayjs(get(item, 'startDate')).toISOString(),
|
||||
end: dayjs(get(item, 'endDate')).toISOString(),
|
||||
},
|
||||
} as Education,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Awards
|
||||
try {
|
||||
const awards: any[] = get(jsonResume, 'awards.items', []);
|
||||
awards.forEach((award) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
awards: {
|
||||
items: [
|
||||
...get(resume, 'sections.awards.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
title: get(award, 'title'),
|
||||
awarder: get(award, 'awarder'),
|
||||
summary: get(award, 'summary'),
|
||||
date: dayjs(get(award, 'date')).toISOString(),
|
||||
} as Award,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Certifications
|
||||
try {
|
||||
const certifications: any[] = get(jsonResume, 'certifications.items', []);
|
||||
certifications.forEach((certificate) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
certifications: {
|
||||
items: [
|
||||
...get(resume, 'sections.certifications.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: get(certificate, 'title'),
|
||||
issuer: get(certificate, 'issuer'),
|
||||
summary: get(certificate, 'summary'),
|
||||
date: dayjs(get(certificate, 'date')).toISOString(),
|
||||
} as Certificate,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Skills
|
||||
try {
|
||||
const skills: any[] = get(jsonResume, 'skills.items', []);
|
||||
skills.forEach((skill) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
skills: {
|
||||
items: [
|
||||
...get(resume, 'sections.skills.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: get(skill, 'name'),
|
||||
level: get(skill, 'level'),
|
||||
levelNum: 5,
|
||||
} as Skill,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Languages
|
||||
try {
|
||||
const languages: any[] = get(jsonResume, 'languages.items', []);
|
||||
languages.forEach((language) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
languages: {
|
||||
items: [
|
||||
...get(resume, 'sections.languages.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: get(language, 'name'),
|
||||
level: get(language, 'fluency'),
|
||||
levelNum: 5,
|
||||
} as Language,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Hobbies
|
||||
try {
|
||||
const hobbies: any[] = get(jsonResume, 'hobbies.items', []);
|
||||
hobbies.forEach((hobby) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
interests: {
|
||||
items: [
|
||||
...get(resume, 'sections.interests.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: get(hobby, 'name'),
|
||||
keywords: get(hobby, 'keywords', []),
|
||||
} as Interest,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// References
|
||||
try {
|
||||
const references: any[] = get(jsonResume, 'references.items', []);
|
||||
references.forEach((reference) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
references: {
|
||||
items: [
|
||||
...get(resume, 'sections.references.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: get(reference, 'name'),
|
||||
relationship: get(reference, 'position'),
|
||||
phone: get(reference, 'phone'),
|
||||
email: get(reference, 'email'),
|
||||
summary: get(reference, 'summary'),
|
||||
} as Reference,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Projects
|
||||
try {
|
||||
const projects: any[] = get(jsonResume, 'projects.items', []);
|
||||
projects.forEach((project) => {
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
sections: {
|
||||
projects: {
|
||||
items: [
|
||||
...get(resume, 'sections.projects.items', []),
|
||||
{
|
||||
id: uuidv4(),
|
||||
name: get(project, 'title'),
|
||||
summary: get(project, 'summary'),
|
||||
keywords: get(project, 'keywords'),
|
||||
url: get(project, 'link'),
|
||||
date: {
|
||||
start: dayjs(get(project, 'date')).toISOString(),
|
||||
},
|
||||
} as Project,
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// pass through
|
||||
}
|
||||
|
||||
// Metadata
|
||||
const template = get(jsonResume, 'metadata.template');
|
||||
const templateWhitelist = ['onyx', 'pikachu', 'gengar', 'castform', 'glalie'];
|
||||
merge<Partial<Resume>, DeepPartial<Resume>>(resume, {
|
||||
metadata: {
|
||||
...get(resume, 'metadata'),
|
||||
typography: {
|
||||
family: {
|
||||
heading: get(jsonResume, 'metadata.font'),
|
||||
body: get(jsonResume, 'metadata.font'),
|
||||
},
|
||||
size: {
|
||||
heading: get(jsonResume, 'metadata.fontSize'),
|
||||
body: get(jsonResume, 'metadata.fontSize'),
|
||||
},
|
||||
},
|
||||
theme: {
|
||||
background: get(jsonResume, 'metadata.colors.background'),
|
||||
primary: get(jsonResume, 'metadata.colors.primary'),
|
||||
text: get(jsonResume, 'metadata.colors.text'),
|
||||
},
|
||||
locale: get(jsonResume, 'metadata.language'),
|
||||
template: templateWhitelist.includes(template) ? template : 'kakuna',
|
||||
},
|
||||
});
|
||||
|
||||
return this.resumeService.import(resume, userId);
|
||||
} catch {
|
||||
throw new HttpException('You must upload a valid JSON Resume file.', HttpStatus.BAD_REQUEST);
|
||||
} finally {
|
||||
await unlink(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user