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

Added getAllMembers Endpoint #9

Merged
merged 6 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/backend/src/users/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export enum Status {
MEMBER = 'MEMBER',
RECRUITER = 'RECRUITER',
ADMIN = 'ADMIN',
ALUMNI = 'ALUMNI',
APPLICANT = 'APPLICANT',
}
26 changes: 22 additions & 4 deletions apps/backend/src/users/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

import { Entity, Column, ObjectIdColumn, ObjectId } from 'typeorm';
import { Status } from './types';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@ObjectIdColumn() // https://github.com/typeorm/typeorm/issues/1584
userId: ObjectId;

@Column()
status: Status;

@Column()
firstName: string;
Expand All @@ -13,4 +16,19 @@ export class User {

@Column()
email: string;

@Column()
profilePicture: string;

Copy link
Member

Choose a reason for hiding this comment

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

🔧 Can we allow profilePicture to be null? We probably don't need/want the pictures of applicants

Copy link
Author

Choose a reason for hiding this comment

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

Yes! We can go back and change this to allow the profilePicture to be null.

@Column()
linkedin: string | null;

@Column()
github: string | null;

@Column()
team: string | null;

Copy link
Member

Choose a reason for hiding this comment

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

⛏️ Can we define enums for the team and role fields (similar to Status for the status field)?

Copy link
Author

@kimharr24 kimharr24 Sep 27, 2023

Choose a reason for hiding this comment

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

Sure, we can also define enums for these fields. To account for people with multiple roles, would we want to change the data type to Role[]?

Copy link
Member

Choose a reason for hiding this comment

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

Yup, that sounds good!

@Column()
role: string | null;
}
15 changes: 12 additions & 3 deletions apps/backend/src/users/users.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Controller, Get } from '@nestjs/common';
import {
DefaultValuePipe,
ParseBoolPipe,
Query,
Controller,
Get,
} from '@nestjs/common';

import { UsersService } from './users.service';

Expand All @@ -7,7 +13,10 @@ export class UsersController {
constructor(private readonly usersService: UsersService) {}

@Get()
getAllUsers() {
return this.usersService.findAll();
getAllMembers(
@Query('getAllMembers', new DefaultValuePipe(false), ParseBoolPipe)
Copy link
Member

Choose a reason for hiding this comment

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

💭 Just thinking out loud but I have a feeling we'll want this route to be a more generic route that can be used to retrieve users of an arbitrary list of statuses instead of having separate routes to get different subsets of users

Copy link
Author

Choose a reason for hiding this comment

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

For sure, we can go back to this and change it to be more generic in the future (unless you want us to refactor it now)

Copy link
Member

Choose a reason for hiding this comment

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

Yeah let's change it in a future PR for sure

getAllMembers: boolean,
Copy link
Member

Choose a reason for hiding this comment

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

❓ Does @Query('getAllMembers', ParseBoolPipe) getAllMembers: boolean also work here? (Also just a side note that the getAllMembers param should actually be called allMembers)

Copy link
Author

Choose a reason for hiding this comment

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

I believe that breaks the endpoint when you don't pass in any query parameters (i.e., localhost:3000/api/users/). This is because ParseBoolPipe expects a non-null, non-undefined value as inputs. Since we want the default value to be false when no query parameter is passed, as per the ticket, we decided to use the DefaultValuePipe. We can also change the param name to allMembers

Copy link
Member

Choose a reason for hiding this comment

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

Ahh yep, makes sense!

) {
return this.usersService.findAll(getAllMembers);
}
}
37 changes: 32 additions & 5 deletions apps/backend/src/users/users.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
import { Injectable } from '@nestjs/common';
import { UnauthorizedException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { MongoRepository } from 'typeorm';

import { User } from './user.entity';
import { Status } from './types';
import { ObjectId } from 'mongodb';

@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
private usersRepository: MongoRepository<User>,
) {}
Copy link
Member

Choose a reason for hiding this comment

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

❓ Is there a reason for preferring MongoRepository over Repository?

Copy link
Author

@kimharr24 kimharr24 Sep 27, 2023

Choose a reason for hiding this comment

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

As far as I understand, Repository has some bugs with MongoDB operators. For example, I ran into an issue querying with the OR operator: usersRepository.find({ where: [{ field1: value1 }, { field2: value2 }]}) kept failing even though the docs says it should work. Repository doesn't support $ operators. MongoRepository is designed to use native MongoDB $ operators. I was able to run the above with no issue using usersRepository.find({ where: { $or: [{ field1: { $eq: value1 } }, { field2: { $eq: value2 } }]}}). We could keep using Repository, but I think it could get glitchy.


findAll(): Promise<User[]> {
return this.usersRepository.find();
async findAll(getAllMembers: boolean): Promise<User[]> {
if (!getAllMembers) return [];

const exampleUser: User = {
userId: new ObjectId('a0f3efa0f3efa0f3efa0f3ef'),
status: Status.ADMIN,
firstName: 'jimmy',
lastName: 'jimmy2',
email: 'jimmy.jimmy2@mail.com',
profilePicture: null,
linkedin: null,
github: null,
team: null,
role: null,
};

if (exampleUser.status == Status.APPLICANT) {
throw new UnauthorizedException();
Copy link
Member

Choose a reason for hiding this comment

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

⛏️ Can we use === here and on line 48? Generally, there's no reason to prefer == over === (with one common exception of variable == null as a shortcut for variable === null || variable === undefined) and will only lead to not-so-obvious bugs:

console.log([1] == true) // true
console.log([2] == true) // false
console.log(![] == []) // true

}

const users: User[] = await this.usersRepository.find({
where: {
status: { $not: { $eq: Status.APPLICANT } },
},
});

return users;
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "0.0.0",
"license": "MIT",
"scripts": {
"format:check": "prettier --check apps/{frontend,backend}/src/**/*.{js,ts,tsx}",
"format": "prettier --write apps/{frontend,backend}/src/**/*.{js,ts,tsx}",
"format:check": "prettier --no-error-on-unmatched-pattern --check apps/{frontend,backend}/src/**/*.{js,ts,tsx}",
"format": "prettier --no-error-on-unmatched-pattern --write apps/{frontend,backend}/src/**/*.{js,ts,tsx}",
"lint:check": "eslint apps/frontend --ext .ts,.tsx && eslint apps/backend --ext .ts,.tsx",
"lint": "eslint apps/frontend --ext .ts,.tsx --fix && eslint apps/backend --ext .ts,.tsx --fix",
"prepush": "yarn run format:check && yarn run lint:check",
Expand Down
Loading