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: migrate 'profile/info' route to nestjs #2420

Closed
wants to merge 4 commits into from

Conversation

stas-laniuk
Copy link
Contributor

@stas-laniuk stas-laniuk commented Feb 1, 2024

🟒 Add deploy label if you want to deploy this Pull Request to staging environment

πŸ§‘β€βš–οΈ Pull Request Naming Convention

  • Title should follow Conventional Commits
  • Do not put issue id in title
  • Do not put WIP in title. Use Draft PR functionality
  • Consider to add area:* label(s)
  • I followed naming convention rules

πŸ€” This is a ...

  • New feature
  • Bug fix
  • Performance optimization
  • Refactoring
  • Test Case
  • Documentation update
  • Other

πŸ”— Related issue link

#2394

πŸ’‘ Background and solution

added nestJs route handling for GET 'profile/info' route
removed koa-related GET 'profile/info' rote handling code (currently in progress)
fixed typos: Endorment -> Endorsement, isContactsNodesVisible -> isContactsNotesVisible(bug)
verification screenshots are below:

screenshots are presented in pairs: backed by koa in master branch/backed by nestjs in feature branch whole bunch of screenshots: https://drive.google.com/drive/folders/1s5qb-Um8lwAyd-sGzQUfMeEBdx0ffgBb?usp=drive_link

isAdmin: true:
profileInfo page: self, mentor, no relation:
localhost_3000_profile_admin_koa
localhost_3000_profile_admin_nest

localhost_3000_profile_githubId=anik188_admin_koa
localhost_3000_profile_githubId=anik188_admin_nest

localhost_3000_profile_githubId=apalchys_admin_koa
localhost_3000_profile_githubId=apalchys_admin_nest

isAdmin: false:
profileInfo page: self, mentor, no relation:
localhost_3000_profile_no-admin_koa
localhost_3000_profile_no-admin_nest

localhost_3000_profile_githubId=anik188_no-admin_koa
localhost_3000_profile_githubId=anik188_no-admin_nest

localhost_3000_profile_githubId=apalchys_no-admin_koa
localhost_3000_profile_githubId=apalchys_no-admin_nest

dashboard page:
localhost_3000_course_student_dashboard_course=test-course_no-admin_koa
localhost_3000_course_student_dashboard_course=test-course_no-admin_nest

β˜‘οΈ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Database migration is added or not needed
  • Documentation is updated/provided or not needed
  • Changes are tested locally

@stas-laniuk stas-laniuk marked this pull request as ready for review February 8, 2024 20:21
}

/**
* @deprecated - should be removed once Artsiom A. makes migration of the legacy feedback format
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's better to attach the issue number instead of writing that Artsiom will do it.
#2281"

Comment on lines +197 to +272
async getStageInterviewFeedback(githubId: string): Promise<StageInterviewDetailedFeedback[]> {
const data = await this.stageInterviewRepository
.createQueryBuilder('stageInterview')
.select('"stageInterview"."decision" AS "decision"')
.addSelect('"stageInterview"."isGoodCandidate" AS "isGoodCandidate"')
.addSelect('"stageInterview"."score" AS "interviewScore"')
.addSelect('"course"."name" AS "courseName"')
.addSelect('"course"."fullName" AS "courseFullName"')
.addSelect('"stageInterviewFeedback"."json" AS "interviewResultJson"')
.addSelect('"stageInterviewFeedback"."updatedDate" AS "interviewFeedbackDate"')
.addSelect('"stageInterviewFeedback"."version" AS "feedbackVersion"')
.addSelect('"userMentor"."firstName" AS "interviewerFirstName"')
.addSelect('"userMentor"."lastName" AS "interviewerLastName"')
.addSelect('"userMentor"."githubId" AS "interviewerGithubId"')
.addSelect('"courseTask"."maxScore" AS "maxScore"')
.leftJoin(Student, 'student', '"student"."id" = "stageInterview"."studentId"')
.leftJoin(User, 'user', '"user"."id" = "student"."userId"')
.leftJoin(Course, 'course', '"course"."id" = "stageInterview"."courseId"')
.leftJoin(
StageInterviewFeedback,
'stageInterviewFeedback',
'"stageInterview"."id" = "stageInterviewFeedback"."stageInterviewId"',
)
.leftJoin(CourseTask, 'courseTask', '"courseTask"."id" = "stageInterview"."courseTaskId"')
.leftJoin(Mentor, 'mentor', '"mentor"."id" = "stageInterview"."mentorId"')
.leftJoin(User, 'userMentor', '"userMentor"."id" = "mentor"."userId"')
.where('"user"."githubId" = :githubId', { githubId })
.andWhere('"stageInterview"."isCompleted" = true')
.orderBy('"course"."updatedDate"', 'ASC')
.getRawMany();

return data
.map((feedbackData: FeedbackData) => {
const {
feedbackVersion,
decision,
interviewFeedbackDate,
interviewerFirstName,
courseFullName,
courseName,
interviewerLastName,
interviewerGithubId,
isGoodCandidate,
interviewScore,
interviewResultJson,
maxScore,
} = feedbackData;
const feedbackTemplate = JSON.parse(interviewResultJson) as any;

const { score, feedback } = !feedbackVersion
? InterviewsService.parseLegacyFeedback(feedbackTemplate)
: {
feedback: feedbackTemplate,
score: interviewScore ?? 0,
};

return {
version: feedbackVersion ?? 0,
date: interviewFeedbackDate,
decision,
isGoodCandidate,
courseName,
courseFullName,
feedback,
score,
interviewer: {
name:
this.userService.getFullName({ firstName: interviewerFirstName, lastName: interviewerLastName }) ||
interviewerGithubId,
githubId: interviewerGithubId,
},
maxScore,
};
})
.filter(Boolean);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should do something like this?

  private async getFeedbackData(githubId: string): Promise<FeedbackData[]> {
    return this.stageInterviewRepository
      .createQueryBuilder('stageInterview')
      // ... addSelects ...
      .leftJoin(Student, 'student', '"student"."id" = "stageInterview"."studentId"')
      // ... other leftJoins ...
      .where('"user"."githubId" = :githubId', { githubId })
      .andWhere('"stageInterview"."isCompleted" = true')
      .orderBy('"course"."updatedDate"', 'ASC')
      .getRawMany();
  }

  private parseFeedbackData(feedbackData: FeedbackData): StageInterviewDetailedFeedback {
    // ... existing mapping logic ...
  }

  async getStageInterviewFeedback(githubId: string): Promise<StageInterviewDetailedFeedback[]> {
    const feedbackData = await this.getFeedbackData(githubId);
    return feedbackData.map(feedbackData => this.parseFeedbackData(feedbackData)).filter(Boolean);
  }

Copy link
Contributor

@AlreadyBored AlreadyBored left a comment

Choose a reason for hiding this comment

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

Thank you, I left some comments, please take a look :)

Comment on lines +60 to 63
const profileInfoExtendedWithCv = {
...profileInfo,
...data,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I see nothing related with CV above, why do we have CV in name of this variable? πŸ™ƒ

@@ -44,7 +44,8 @@ export interface GeneralInfo {
aboutMyself?: string | null;
location: Location;
educationHistory?: any | null;
englishLevel?: EnglishLevel | null;
// TODO: String type is too abstract for englishLevel.
Copy link
Contributor

Choose a reason for hiding this comment

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

Then why do we have it here? Probably you've misconfigured some BE API decorators, could you please check?

Comment on lines +229 to +243
.map((feedbackData: FeedbackData) => {
const {
feedbackVersion,
decision,
interviewFeedbackDate,
interviewerFirstName,
courseFullName,
courseName,
interviewerLastName,
interviewerGithubId,
isGoodCandidate,
interviewScore,
interviewResultJson,
maxScore,
} = feedbackData;
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
.map((feedbackData: FeedbackData) => {
const {
feedbackVersion,
decision,
interviewFeedbackDate,
interviewerFirstName,
courseFullName,
courseName,
interviewerLastName,
interviewerGithubId,
isGoodCandidate,
interviewScore,
interviewResultJson,
maxScore,
} = feedbackData;
.map(({
feedbackVersion,
decision,
interviewFeedbackDate,
interviewerFirstName,
courseFullName,
courseName,
interviewerLastName,
interviewerGithubId,
isGoodCandidate,
interviewScore,
interviewResultJson,
maxScore,
}: FeedbackData) => {

Comment on lines +246 to +251
const { score, feedback } = !feedbackVersion
? InterviewsService.parseLegacyFeedback(feedbackTemplate)
: {
feedback: feedbackTemplate,
score: interviewScore ?? 0,
};
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
const { score, feedback } = !feedbackVersion
? InterviewsService.parseLegacyFeedback(feedbackTemplate)
: {
feedback: feedbackTemplate,
score: interviewScore ?? 0,
};
const { score, feedback } = feedbackVersion
? {
feedback: feedbackTemplate,
score: interviewScore ?? 0,
} : InterviewsService.parseLegacyFeedback(feedbackTemplate);

class PublicVisibilitySettings {
@ApiProperty()
@IsBoolean()
all: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd propose to use more semantic name for this flag, like getAll or requestAll

async getStats(githubId: string, permissions: Permissions): Promise<StudentStats[]> {
const { isCoreJsFeedbackVisible, isExpellingReasonVisible } = permissions;

const query = await this.studentRepository
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above

interviewerLastName,
certificateId,
rank,
}: any) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

please no any

Comment on lines +181 to +182
.sort((a: any, b: any) => a.endDate - b.endDate)
.map((task: any) => omit(task, 'endDate'));
Copy link
Contributor

Choose a reason for hiding this comment

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

please no any

Comment on lines +17 to +29
async getUserInfo(githubId: string, permissions: Permissions): Promise<UserInfo> {
const {
isAboutVisible,
isEducationVisible,
isEnglishVisible,
isPhoneVisible,
isEmailVisible,
isTelegramVisible,
isSkypeVisible,
isContactsNotesVisible,
isLinkedInVisible,
isWhatsAppVisible,
} = permissions;
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
async getUserInfo(githubId: string, permissions: Permissions): Promise<UserInfo> {
const {
isAboutVisible,
isEducationVisible,
isEnglishVisible,
isPhoneVisible,
isEmailVisible,
isTelegramVisible,
isSkypeVisible,
isContactsNotesVisible,
isLinkedInVisible,
isWhatsAppVisible,
} = permissions;
async getUserInfo(githubId: string, {
isAboutVisible,
isEducationVisible,
isEnglishVisible,
isPhoneVisible,
isEmailVisible,
isTelegramVisible,
isSkypeVisible,
isContactsNotesVisible,
isLinkedInVisible,
isWhatsAppVisible,
}: Permissions): Promise<UserInfo> {

isWhatsAppVisible,
} = permissions;

const query = this.userRepository
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants