diff --git a/apps/backend/src/user/user.service.ts b/apps/backend/src/user/user.service.ts index 363cdc2..86319d6 100644 --- a/apps/backend/src/user/user.service.ts +++ b/apps/backend/src/user/user.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { DynamoDbService } from '../dynamodb'; import { UserInputModel, UserStatus, Role } from './user.model'; import { NewUserInput } from '../dtos/newUserDTO'; -import { UserModel, EditUserModel } from "./user.model"; +import { UserModel, EditUserModel } from './user.model'; @Injectable() export class UserService { @@ -110,174 +110,133 @@ export class UserService { status: { S: UserStatus.PENDING }, }; }; -} - - - - public async editUser(userId: number, model :EditUserModel): Promise { - - try { - // A list of commands for each edit, only adds if exists - const commands = []; - const expressionAttributeValues :Record = {}; - const expressionAttributeNames: Record = {}; // Added for aliases - - const originalUser = await this.getUser(userId); - - - - if (model.firstName) { - commands.push(`firstName = :firstName`); - expressionAttributeValues[":firstName"] = { S: model.firstName }; - } - - if (model.lastName) { - commands.push(`lastName = :lastName`); - expressionAttributeValues[":lastName"] = { S: model.lastName }; - } - - if (model.phoneNumber) { - commands.push(`phoneNumber = :phoneNumber`); - expressionAttributeValues[":phoneNumber"] = { S: model.phoneNumber }; - } - - if (model.siteId) { - // Ensure siteId is treated as a string - const siteIdStr = model.siteId.toString(); - - // Use list_append to add the new siteId to the siteIds list - commands.push(`siteIds = list_append(siteIds, :siteId)`); - expressionAttributeValues[":siteId"] = { L: [{ N: siteIdStr }] }; - - // Check if siteId exists in greenInfraBostonSites using getItem - const siteKey = { siteId: { S: siteIdStr } }; - const siteCheckResult = await this.dynamoDbService.getItem('greenInfraBostonSites', siteKey); - - if(originalUser.siteIds.includes(model.siteId)) { - return {statusCode: 400, message: "Site already exists in user's siteIds"}; - } - - if (!siteCheckResult) { - return {statusCode: 400, message: "Site does not exist"}; - } - } - - if (model.status) { - commands.push(`#s = :status`); - expressionAttributeValues[":status"] = { S: model.status }; - expressionAttributeNames["#s"] = "status"; // Define the alias - } + public async editUser(userId: number, model: EditUserModel): Promise { + try { + // A list of commands for each edit, only adds if exists + const commands = []; + const expressionAttributeValues: Record = {}; + const expressionAttributeNames: Record = {}; // Added for aliases - // Make sure commands aren't empty - if (commands.length === 0) { - throw new Error("No fields to update"); - } + const originalUser = await this.getUser(userId); + if (model.firstName) { + commands.push(`firstName = :firstName`); + expressionAttributeValues[':firstName'] = { S: model.firstName }; + } - // Combine into one update expression and update the user - const updateExpr = `SET ${commands.join(", ")}`; - const key = { 'userId' : {N: userId.toString()}}; - const data = await this.dynamoDbService.updateItemWithExpression(this.tableName, key, updateExpr,expressionAttributeValues, expressionAttributeNames) - - const result = await this.getUser(userId); - + if (model.lastName) { + commands.push(`lastName = :lastName`); + expressionAttributeValues[':lastName'] = { S: model.lastName }; + } - if (!data) { - return {statusCode: 400, message: "No user found with id: " + userId}; - } - return result; - } catch(e) { - throw new Error(`Error updating data for user with id: ${userId}: ${e.message}`); - } - } - + if (model.phoneNumber) { + commands.push(`phoneNumber = :phoneNumber`); + expressionAttributeValues[':phoneNumber'] = { S: model.phoneNumber }; + } - // Run backend on postman please, not SwaggerUI - public async getUserByStatus(status: UserStatus): Promise { - try { - const filterExpression = "#user_status = :statusOf"; - const expressionAttributeValues = { ":statusOf": { S: status } }; - const expressionAttributeNames = {"#user_status":"status"} - - const data = await this.dynamoDbService.scanTable( - this.tableName, - filterExpression, - expressionAttributeValues, - expressionAttributeNames - - ); - - return data.map(item => this.mapDynamoDBItemToUserModelV2(item)); // added data - } catch (error) { - console.error("Error fetching users by status:", error); - throw new Error(`Error fetching users by status: ${error.message}`); + if (model.siteId) { + // Ensure siteId is treated as a string + const siteIdStr = model.siteId.toString(); + + // Use list_append to add the new siteId to the siteIds list + commands.push(`siteIds = list_append(siteIds, :siteId)`); + expressionAttributeValues[':siteId'] = { L: [{ N: siteIdStr }] }; + + // Check if siteId exists in greenInfraBostonSites using getItem + const siteKey = { siteId: { S: siteIdStr } }; + const siteCheckResult = await this.dynamoDbService.getItem( + 'greenInfraBostonSites', + siteKey, + ); + + if (originalUser.siteIds.includes(model.siteId)) { + return { + statusCode: 400, + message: "Site already exists in user's siteIds", + }; } - } - + if (!siteCheckResult) { + return { statusCode: 400, message: 'Site does not exist' }; + } + } - /** - * Maps a user's data from DynamoDB to a UserModel object. - * @param objectId the user's id - * @param data the user's data from DynamoDB - * @throws Error if the user's status or role is invalid - * @returns the user's information as a UserModel object - */ - private mapDynamoDBItemToUserModel(objectId: number, data?: {[key: string]: any}): UserModel { + if (model.status) { + commands.push(`#s = :status`); + expressionAttributeValues[':status'] = { S: model.status }; + expressionAttributeNames['#s'] = 'status'; // Define the alias + } - const siteIds = data["siteIds"].L.map(item => Number(item.N)) ?? []; + // Make sure commands aren't empty + if (commands.length === 0) { + throw new Error('No fields to update'); + } + // Combine into one update expression and update the user + const updateExpr = `SET ${commands.join(', ')}`; + const key = { userId: { N: userId.toString() } }; + const data = await this.dynamoDbService.updateItemWithExpression( + this.tableName, + key, + updateExpr, + expressionAttributeValues, + expressionAttributeNames, + ); - return { - userId: objectId, - firstName: data['firstName'].S, - lastName: data['lastName'].S, - email: data['email'].S, - phoneNumber: data['phoneNumber'].N, - siteIds: siteIds, - zipCode: data['zipCode'].S, - birthDate: new Date(data['birthDate'].S), - role: data['role'].S, - status: data['status'].S - }; - } + const result = await this.getUser(userId); - private PostInputToUserVolunteerModel = (input: NewUserInput): UserInputModel => { - return { - userId: {N: "0"}, - firstName: {S: input.firstName}, - lastName: {S: input.lastName}, - phoneNumber: {S: input.phoneNumber}, - email: {S: input.email}, - zipCode: {S: input.zipCode}, - birthDate: {S: input.birthDate}, - role: {S: Role.VOLUNTEER}, - siteIds: {S: "null"}, - status: {S: UserStatus.PENDING} - }; - } - /** - * Maps a user's data from DynamoDB to a UserModel object. - * @param data the user's data from DynamoDB - * @returns the user's information as a UserModel object - */ - private mapDynamoDBItemToUserModelV2(data: { [key: string]: any }): UserModel { - return { - userId: data["userId"].N, - firstName: data["firstName"].S, - lastName: data["lastName"].S, - email: data["email"].S, - phoneNumber: parseInt(data["phoneNumber"].N), - siteIds: data["siteIds"]?.NS?.map(Number) ?? [], - zipCode: parseInt(data["zipCode"].N), - birthDate: new Date(data["birthDate"].S), - role: data["role"].S, - status: data["status"].S as UserStatus, - }; + if (!data) { + return { statusCode: 400, message: 'No user found with id: ' + userId }; + } + return result; + } catch (e) { + throw new Error( + `Error updating data for user with id: ${userId}: ${e.message}`, + ); } + } + // Run backend on postman please, not SwaggerUI + public async getUserByStatus(status: UserStatus): Promise { + try { + const filterExpression = '#user_status = :statusOf'; + const expressionAttributeValues = { ':statusOf': { S: status } }; + const expressionAttributeNames = { '#user_status': 'status' }; + const data = await this.dynamoDbService.scanTable( + this.tableName, + filterExpression, + expressionAttributeValues, + expressionAttributeNames, + ); + return data.map((item) => this.mapDynamoDBItemToUserModelV2(item)); // added data + } catch (error) { + console.error('Error fetching users by status:', error); + throw new Error(`Error fetching users by status: ${error.message}`); + } + } + /** + * Maps a user's data from DynamoDB to a UserModel object. + * @param data the user's data from DynamoDB + * @returns the user's information as a UserModel object + */ + private mapDynamoDBItemToUserModelV2(data: { + [key: string]: any; + }): UserModel { + return { + userId: data['userId'].N, + firstName: data['firstName'].S, + lastName: data['lastName'].S, + email: data['email'].S, + phoneNumber: parseInt(data['phoneNumber'].N), + siteIds: data['siteIds']?.NS?.map(Number) ?? [], + zipCode: parseInt(data['zipCode'].N), + birthDate: new Date(data['birthDate'].S), + role: data['role'].S, + status: data['status'].S as UserStatus, + }; + } }