Skip to content

Commit

Permalink
Merge branch 'main' into braydon/add-user-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
owen-sellner authored Mar 19, 2024
2 parents 911381b + db3b1de commit 70805d6
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 4 deletions.
1 change: 1 addition & 0 deletions backend/graphql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const graphQLMiddlewares = {
deleteSimpleEntity: authorizedByAllRoles(),
createUser: authorizedByAdmin(),
updateUser: authorizedByAdmin(),
updateUserRole: authorizedByAdmin(),
deleteUserById: authorizedByAdmin(),
deleteUserByEmail: authorizedByAdmin(),
logout: isAuthorizedByUserId("userId"),
Expand Down
8 changes: 7 additions & 1 deletion backend/graphql/resolvers/userResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import UserService from "../../services/implementations/userService";
import IAuthService from "../../services/interfaces/authService";
import IEmailService from "../../services/interfaces/emailService";
import IUserService from "../../services/interfaces/userService";
import { CreateUserDTO, UpdateUserDTO, UserDTO } from "../../types";
import { CreateUserDTO, Role, UpdateUserDTO, UserDTO } from "../../types";
import { generateCSV } from "../../utilities/CSVUtils";

const userService: IUserService = new UserService();
Expand Down Expand Up @@ -50,6 +50,12 @@ const userResolvers = {
): Promise<UserDTO> => {
return userService.updateUserById(id, user);
},
updateUserRole: async (
_parent: undefined,
{ id, role }: { id: string; role: Role },
): Promise<void> => {
return userService.updateUserRoleById(id, role);
},
deleteUserById: async (
_parent: undefined,
{ id }: { id: string },
Expand Down
1 change: 1 addition & 0 deletions backend/graphql/types/userType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const userType = gql`
extend type Mutation {
createUser(user: CreateUserDTO!): UserDTO!
updateUser(id: ID!, user: UpdateUserDTO!): UserDTO!
updateUserRole(id: ID!, role: Role!): ID
deleteUserById(id: ID!): ID
deleteUserByEmail(email: String!): ID
}
Expand Down
2 changes: 2 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"graphql-upload": "^12.0.0",
"json2csv": "^5.0.6",
"lodash": "^4.17.21",
"mongodb": "3.6.8",
"mongoose": "^5.12.12",
"multer": "^1.4.2",
"node-fetch": "^2.6.1",
Expand All @@ -48,6 +49,7 @@
"yamljs": "^0.3.0"
},
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.10",
"@types/dotenv": "^8.2.0",
Expand Down
48 changes: 48 additions & 0 deletions backend/seeding/seedEntities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { faker } from "@faker-js/faker";

Check failure on line 1 in backend/seeding/seedEntities.ts

View workflow job for this annotation

GitHub Actions / run-lint

'@faker-js/faker' should be listed in the project's dependencies, not devDependencies
import { MongoClient } from "mongodb";
import { Entity } from "../models/entity.model";

function createRandomEntity(): Entity {
return {
id: faker.string.uuid(),
stringField: faker.word.words({ count: { min: 1, max: 10 } }),
intField: faker.number.int({ min: 2015, max: 2024 }),
enumField: faker.helpers.arrayElement(["A", "B", "C", "D"]),
stringArrayField: faker.helpers.arrayElements([
"One",
"Two",
"Three",
"Four",
"Five",
]),
boolField: faker.datatype.boolean(),
fileName: faker.word.noun(),
} as Entity;
}

async function seedEntities(): Promise<void> {
const uri = process.env.MG_DATABASE_URL;
if (uri === undefined) {
return;
}
const client = new MongoClient(uri, {
useNewUrlParser: true,
// useUnifiedTopology: true,
});

await client.connect();
const collection = client.db("test").collection("entities");

// collection.drop(); // drop() destroys all data in the collection, not sure if we want to every time

const entityData: Entity[] = [];

for (let i = 0; i < 10; i += 1) {
const entity = createRandomEntity();
entityData.push(entity);
}
collection.insertMany(entityData);
client.close();
}

seedEntities();
26 changes: 23 additions & 3 deletions backend/services/implementations/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class UserService implements IUserService {
// must explicitly specify runValidators when updating through findByIdAndUpdate
oldUser = await MgUser.findByIdAndUpdate(
userId,
{ firstName: user.firstName, lastName: user.lastName, role: user.role },
{ firstName: user.firstName, lastName: user.lastName },
{ runValidators: true },
);

Expand All @@ -214,7 +214,6 @@ class UserService implements IUserService {
{
firstName: oldUser.firstName,
lastName: oldUser.lastName,
role: oldUser.role,
},
{ runValidators: true },
);
Expand All @@ -240,10 +239,31 @@ class UserService implements IUserService {
firstName: user.firstName,
lastName: user.lastName,
email: updatedFirebaseUser.email ?? "",
role: user.role,
role: oldUser.role,
};
}

async updateUserRoleById(userId: string, newRole: Role): Promise<void> {
try {
const user = await MgUser.findById(userId);

if (!user) {
throw new Error(`userId ${userId} not found.`);
}
// must explicitly specify runValidators when updating through findByIdAndUpdate
await MgUser.findByIdAndUpdate(
userId,
{ role: newRole },
{ runValidators: true },
);
} catch (error: unknown) {
Logger.error(
`Failed to update user role. Reason = ${getErrorMessage(error)}`,
);
throw error;
}
}

async deleteUserById(userId: string): Promise<void> {
try {
const deletedUser: User | null = await MgUser.findByIdAndDelete(userId);
Expand Down
8 changes: 8 additions & 0 deletions backend/services/interfaces/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ interface IUserService {
*/
updateUserById(userId: string, user: UpdateUserDTO): Promise<UserDTO>;

/**
* Update a user's role - only accessible by Admin.
* @param userId user's id
* @param role the new role for the user
* @throws Error if role update fails
*/
updateUserRoleById(userId: string, role: string): void | PromiseLike<void>;

/**
* Delete a user by id
* @param userId user's userId
Expand Down
5 changes: 5 additions & 0 deletions backend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,11 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"

"@faker-js/faker@^8.4.1":
version "8.4.1"
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.4.1.tgz#5d5e8aee8fce48f5e189bf730ebd1f758f491451"
integrity sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==

"@firebase/[email protected]":
version "0.6.1"
resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.1.tgz#dcbd23030a71c0c74fc95d4a3f75ba81653850e9"
Expand Down

0 comments on commit 70805d6

Please sign in to comment.