From 44ec1d7d1709252c276097eb66728015f69d112d Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 15:56:37 -0600 Subject: [PATCH 01/13] implemented update for user --- api/src/user/dto/update-user.dto.ts | 3 ++ api/src/user/user.controller.ts | 7 +++ api/src/user/user.service.ts | 79 +++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 api/src/user/dto/update-user.dto.ts diff --git a/api/src/user/dto/update-user.dto.ts b/api/src/user/dto/update-user.dto.ts new file mode 100644 index 0000000..4f57edf --- /dev/null +++ b/api/src/user/dto/update-user.dto.ts @@ -0,0 +1,3 @@ +import { User } from './user.dto'; + +export class UpdateUser extends User {} diff --git a/api/src/user/user.controller.ts b/api/src/user/user.controller.ts index 1df3f96..de3f6bd 100644 --- a/api/src/user/user.controller.ts +++ b/api/src/user/user.controller.ts @@ -11,6 +11,7 @@ import { UserService } from './user.service'; import { CreateUser } from './dto/create-user.dto'; import { UserType } from './dto/user.dto'; import { ApiTags } from '@nestjs/swagger'; +import { UpdateUser } from './dto/update-user.dto'; @ApiTags('user') @Controller('/api/user') @@ -44,4 +45,10 @@ export class UserController { findOne(@Param('lsu_id') lsu_id: number) { return this.userService.findOne(lsu_id); } + + /* WORKING implementation */ + @Put(':lsu_id') + update(@Body() updateUser: UpdateUser, @Param('lsu_id') lsu_id: number) { + return this.userService.update(updateUser, lsu_id); + } } diff --git a/api/src/user/user.service.ts b/api/src/user/user.service.ts index 4ad1efc..8577e09 100644 --- a/api/src/user/user.service.ts +++ b/api/src/user/user.service.ts @@ -8,6 +8,7 @@ import { import { Pool, QueryConfig } from 'pg'; import { PG_CONNECTION } from 'src/connection'; import { CreateUser } from './dto/create-user.dto'; +import { UpdateUser } from './dto/update-user.dto'; import { User, UserType } from './dto/user.dto'; @Injectable() @@ -153,4 +154,82 @@ export class UserService { ); } } + + /* WORKING implementation */ + async update(updateUser: UpdateUser, old_lsu_id: number) { + const { + lsu_id, + email, + first_name, + last_name, + phone_number, + department, + admin, + } = updateUser; + + const findQuery: QueryConfig = { + name: 'select_user_by_id', + text: 'SELECT lsu_id FROM "user" WHERE lsu_id = $1', + values: [old_lsu_id], + }; + try { + const res = await this.connection.query(findQuery); + + /* Test to see if student exists */ + if (res.rows.length < 1) { + /*Throw custom error to be handled in catch*/ + throw new Error('BAD_REQUEST'); + } + } catch (error) { + /* Catch custom error if user does not exist + Then throw Bad Request HttpException + */ + if (error.message === 'BAD_REQUEST') { + throw new HttpException( + { + error: `User with lsu_id ${lsu_id} DOES NOT EXIST`, + }, + HttpStatus.BAD_REQUEST, + ); + } + /* Catch postgres error and throw Internal Error HttpException */ + throw new HttpException( + { + message: findQuery, + error: error, + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + + /* Update user in db */ + const updateQuery: QueryConfig = { + name: 'update_user', + + text: + 'UPDATE "user" SET lsu_id = $1, email = $2, first_name = $3, last_name = $4, phone_number = $5, department = $6, admin = $7 WHERE lsu_id = $8 RETURNING *', + values: [ + lsu_id, + email, + first_name, + last_name, + phone_number, + department, + admin, + old_lsu_id, + ], + }; + try { + const res = await this.connection.query(updateQuery); + return res.rows[0]; + } catch (error) { + throw new HttpException( + { + message: updateQuery, + error: error, + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } } From 2e0f275152ce53c0943321130a289c29f7e52ac2 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 16:32:11 -0600 Subject: [PATCH 02/13] implemented update ticket --- api/src/ticket/dto/update-ticket.dto.ts | 8 +- api/src/ticket/ticket.controller.ts | 28 +++--- api/src/ticket/ticket.service.ts | 127 ++++++++++++++++++------ 3 files changed, 117 insertions(+), 46 deletions(-) diff --git a/api/src/ticket/dto/update-ticket.dto.ts b/api/src/ticket/dto/update-ticket.dto.ts index 3f2cbad..8db254a 100644 --- a/api/src/ticket/dto/update-ticket.dto.ts +++ b/api/src/ticket/dto/update-ticket.dto.ts @@ -1,4 +1,10 @@ import { PartialType } from '@nestjs/swagger'; +import { CreateTicket } from './create-ticket.dto'; import { Ticket } from './ticket.dto'; +import { OmitType as Omit } from '@nestjs/swagger'; -export class UpdateTicketDto extends PartialType(Ticket) {} +export class UpdateTicketDto extends Omit(Ticket, [ + 'ticket_id', + 'submission_date', + 'lsu_id', +]) {} diff --git a/api/src/ticket/ticket.controller.ts b/api/src/ticket/ticket.controller.ts index 2521d3e..5ce4f9a 100644 --- a/api/src/ticket/ticket.controller.ts +++ b/api/src/ticket/ticket.controller.ts @@ -18,7 +18,7 @@ import { TicketService } from './ticket.service'; export class TicketController { constructor(private readonly ticketService: TicketService) {} - /* TODO: test implementation */ + /* WORKING Implementation */ @Post() create(@Body() createCombined: CreateCombined) { Logger.log( @@ -35,44 +35,46 @@ export class TicketController { return this.ticketService.create(createCombined); } - /* Working implementation */ + /* WORKING Implementation */ @Get() findAll() { return this.ticketService.findAll(TicketType.ANY); } - /* Working implementation */ + /* WORKING Implementation */ @Get('/opened') findAllOpened() { return this.ticketService.findAll(TicketType.OPENED); } - /* Working implementation */ + /* WORKING Implementation */ @Get('/closed') findAllClosed() { return this.ticketService.findAll(TicketType.CLOSED); } - /* Working implementation */ + /* WORKING Implementation */ @Get('/user/:lsu_id') findAllByLsuId(@Param('lsu_id') lsu_id: number) { return this.ticketService.findAll(lsu_id); } - /* Working implementation */ + /* WORKING Implementation */ @Get(':ticket_id') findOne(@Param('ticket_id') ticket_id: number) { return this.ticketService.findOne(+ticket_id); } - /* TODO: FIX */ - /* NOT WORKING */ - @Put(':id') - update(@Param('id') id: number, @Body() updateTicketDto: UpdateTicketDto) { + /* WORKING Implementation */ + @Put(':ticket_id') + update( + @Param('ticket_id') ticket_id: number, + @Body() updateTicketDto: UpdateTicketDto, + ) { Logger.log( { req: { - http: `PUT /api/ticket/${id}`, - params: id, + http: `PUT /api/ticket/${ticket_id}`, + params: ticket_id, body: updateTicketDto, }, }, @@ -80,6 +82,6 @@ export class TicketController { false, ); - return this.ticketService.update(id, updateTicketDto); + return this.ticketService.update(ticket_id, updateTicketDto); } } diff --git a/api/src/ticket/ticket.service.ts b/api/src/ticket/ticket.service.ts index cc3c40d..b73ba0b 100644 --- a/api/src/ticket/ticket.service.ts +++ b/api/src/ticket/ticket.service.ts @@ -38,27 +38,31 @@ export class TicketService { admin, } = createUser; + /* Check to see if user exists */ const findQuery: QueryConfig = { name: 'select_user_by_id_or_email', text: 'SELECT * FROM "user" WHERE lsu_id = $1 OR email = $2', values: [lsu_id, email], }; - /* Query User by lsuid or email */ try { const res = await this.connection.query(findQuery); - /* Test to see if student exists */ + + /* If user exists abort insert operation by returning early */ if (res.rows.length > 0) { return res.rows[0]; } } catch (error) { throw new HttpException( - { query: findQuery, error: error }, + { + query: findQuery, + error: error, + }, HttpStatus.INTERNAL_SERVER_ERROR, ); } - /* Insert new student into db */ + /* Insert new user into db */ const insertQuery: QueryConfig = { name: 'insert_user', @@ -76,10 +80,15 @@ export class TicketService { }; try { const res = await this.connection.query(insertQuery); + + /* Return newly inserted user */ return res.rows[0]; } catch (error) { throw new HttpException( - { query: insertQuery, error: error }, + { + query: insertQuery, + error: error, + }, HttpStatus.INTERNAL_SERVER_ERROR, ); } @@ -100,9 +109,13 @@ export class TicketService { priority, } = createTicket; + /* Status set to open for new ticket */ const status = 'OPEN'; + + /* Submission date set to current server time */ const submission_date = this.createDate(); + /* Insert new ticket into db */ const query: QueryConfig = { name: 'insert_ticket', text: @@ -120,11 +133,13 @@ export class TicketService { try { const res = await this.connection.query(query); + + /* Return newly inserted ticket */ return res.rows[0]; } catch (error) { throw new HttpException( { - message: query, + query: query, error: error, }, HttpStatus.INTERNAL_SERVER_ERROR, @@ -145,6 +160,8 @@ export class TicketService { operating_system, operating_system_version, } = createDevice; + + /* Insert Device into db */ const query: QueryConfig = { name: 'insert_device', text: @@ -159,11 +176,13 @@ export class TicketService { }; try { const res = await this.connection.query(query); + + /* Return newly inserted device */ return res.rows[0]; } catch (error) { throw new HttpException( { - message: query, + query: query, error: error, }, HttpStatus.INTERNAL_SERVER_ERROR, @@ -193,7 +212,8 @@ export class TicketService { [d.getHours(), d.getMinutes(), d.getSeconds()].join(':'); return date; } - /* TODO: test implementation */ + + /* WORKING Implementation */ async create(createCombined: CreateCombined) { /* Response Accumulator */ let response: Combined; @@ -206,6 +226,8 @@ export class TicketService { const createUser: CreateUser = { ...createCombined, admin: false }; // tickets are created by students so admin is false try { user = await this.createUser(createUser); + + /* Accumulate user to response */ response = { ...response, ...user }; } catch (error) { Logger.error(error); @@ -216,6 +238,8 @@ export class TicketService { const createTicket: CreateTicket = { ...createCombined }; try { ticket = await this.createTicket(createTicket); + + /* Accumulate ticket to response */ response = { ...response, ...ticket }; } catch (error) { Logger.error(error); @@ -229,12 +253,15 @@ export class TicketService { }; try { device = await this.createDevice(createDevice); + + /* Accumulate device to response */ response = { ...response, ...device }; } catch (error) { Logger.error(error); return error; } + /* Return flat object with the intersection of properties from user, ticket, and deivce */ return response; } @@ -276,7 +303,7 @@ export class TicketService { try { const queryRes = await this.connection.query(query); - /* If no tickets */ + /* If no tickets return empty array */ if (queryRes.rows.length === 0) { return []; } @@ -285,7 +312,7 @@ export class TicketService { } catch (error) { throw new HttpException( { - message: query, + query: query, error: error, }, HttpStatus.INTERNAL_SERVER_ERROR, @@ -303,7 +330,7 @@ export class TicketService { try { const queryRes = await this.connection.query(query); - /* If no ticket found */ + /* If no ticket found return empty object*/ if (queryRes.rows.length === 0) { return {}; } @@ -312,7 +339,7 @@ export class TicketService { } catch (error) { throw new HttpException( { - message: query, + query: query, error: error, }, HttpStatus.INTERNAL_SERVER_ERROR, @@ -320,35 +347,71 @@ export class TicketService { } } - /* NOT WORKING implementation */ - async update(id: number, updateTicketDto: UpdateTicketDto) { - id = Number(id); - let keys = []; - let values = []; - - /* unknown properties to be updated */ - for (let key in updateTicketDto) { - if (!!updateTicketDto[key]) { - keys = [...keys, key]; - values = [...values, updateTicketDto[key]]; + /* WORKING Implementation */ + async update(ticket_id: number, updateTicketDto: UpdateTicketDto) { + const { + core_issue, + description, + problem_category, + status, + priority, + } = updateTicketDto; + + /* Check to see if ticket exist */ + const findQuery: QueryConfig = { + name: 'select_ticket_by_ticket_id', + text: 'SELECT * FROM ticket WHERE ticket_id = $1', + values: [ticket_id], + }; + try { + const res = await this.connection.query(findQuery); + + /* If no ticket found throw custom error*/ + if (res.rows.length < 1) { + throw new Error('BAD_REQUEST'); + } + } catch (error) { + /* catch custom error for ticket not found */ + if (error.message === 'BAD_REQUEST') { + /* Throw HttpException for ticket not found */ + throw new HttpException( + { + message: `Ticket with ticket_id: ${ticket_id} DOES NOT EXIST`, + }, + HttpStatus.BAD_REQUEST, + ); } + /* Throw HttpException for postgres errors */ + throw new HttpException( + { + query: findQuery, + error: error, + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); } - /* keys variable defined by interface NOT user so avoids sql injection */ - const columns = keys.map((val, idx) => `${val} = $${idx + 1}`).join(', '); - let txt = String.raw`UPDATE ticket SET ${columns} WHERE ticket_id = $${keys.length}`; - const query = { + /* Update ticket */ + const updateQuery = { name: 'update_ticket', - text: txt, - values: [...values, id], + text: + 'UPDATE ticket SET core_issue = $1, description = $2, problem_category = $3, status = $4, priority = $5 WHERE ticket_id = $6 RETURNING *', + values: [ + core_issue, + description, + problem_category, + status, + priority, + ticket_id, + ], }; try { - const queryRes = await this.connection.query(query, [...values, id]); - return queryRes.rows; + const res = await this.connection.query(updateQuery); + return res.rows[0]; } catch (error) { throw new HttpException( { - message: query, + query: updateQuery, error: error, }, HttpStatus.INTERNAL_SERVER_ERROR, From 747191a016cd65f356ac2988ced8c87ab05b542b Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 16:32:39 -0600 Subject: [PATCH 03/13] updated create-ticket.dto --- api/src/ticket/dto/create-ticket.dto.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/src/ticket/dto/create-ticket.dto.ts b/api/src/ticket/dto/create-ticket.dto.ts index cd893c9..291f253 100644 --- a/api/src/ticket/dto/create-ticket.dto.ts +++ b/api/src/ticket/dto/create-ticket.dto.ts @@ -1,4 +1,8 @@ import { Ticket } from './ticket.dto'; import { OmitType as Omit } from '@nestjs/swagger'; -export class CreateTicket extends Omit(Ticket, ['ticket_id', 'status']) {} +export class CreateTicket extends Omit(Ticket, [ + 'ticket_id', + 'status', + 'submission_date', +]) {} From 714ed3e884429d5a45c643a88ccaa335a9bda5bc Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 16:33:02 -0600 Subject: [PATCH 04/13] updated README with current endpoints --- api/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/api/README.md b/api/README.md index c8821c6..67bc834 100644 --- a/api/README.md +++ b/api/README.md @@ -110,11 +110,12 @@ req: none res: body: {CombineDTO} ``` -Update ticket +Updates one ticket by ticket_id; Does NOT update user or device ``` -/* NOT WORKING */ -PUT /api​/ticket​/{id} +PUT /api​/ticket​/{ticket_id} +req: body: {UpdateTicketDTO} +res: body: {TicketDTO} ``` ## User @@ -155,11 +156,12 @@ GET /api​/user/{lsu_id} res: body: {UserDTO} ``` -Update user +Update user by lsu_id ``` -/* NOT WORKING */ PUT /api/user/{lsu_id} +req: body: {UpdateUserDTO} +res: body: {UserDTO} ``` ## Assign From 19ce4bd46b7dd96379912bea4fd51dd5922971c0 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 16:33:38 -0600 Subject: [PATCH 05/13] added link to github API Readme for more docs --- api/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main.ts b/api/src/main.ts index 99e07ee..ffa443f 100644 --- a/api/src/main.ts +++ b/api/src/main.ts @@ -30,7 +30,7 @@ async function bootstrap() { .setVersion('0.1.0') .setExternalDoc( 'additional documentation', - `http://${HOST}:${PORT}/api/docs/more`, + `https://github.com/cdalton713/CSC_4402_DB_Project/blob/master/api/README.md`, ) .build(); const document = SwaggerModule.createDocument(app, options); From 84db8b705b3cc1f7d549c5dcb234da97d9953e69 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 16:42:18 -0600 Subject: [PATCH 06/13] refactored DTO object names to be consistent --- api/src/ticket/dto/combined.dto.ts | 13 +++-- api/src/ticket/dto/create-combined.dto.ts | 18 +++--- api/src/ticket/dto/create-device.dto.ts | 4 +- api/src/ticket/dto/create-ticket.dto.ts | 4 +- api/src/ticket/dto/device.dto.ts | 2 +- api/src/ticket/dto/ticket.dto.ts | 2 +- api/src/ticket/dto/update-ticket.dto.ts | 6 +- api/src/ticket/ticket.controller.ts | 8 +-- api/src/ticket/ticket.service.ts | 71 ++++++++++++----------- api/src/user/dto/create-user.dto.ts | 4 +- api/src/user/dto/update-user.dto.ts | 4 +- api/src/user/dto/user.dto.ts | 2 +- api/src/user/user.controller.ts | 13 +++-- api/src/user/user.service.ts | 25 ++++---- 14 files changed, 92 insertions(+), 84 deletions(-) diff --git a/api/src/ticket/dto/combined.dto.ts b/api/src/ticket/dto/combined.dto.ts index 50d1870..19a9be4 100644 --- a/api/src/ticket/dto/combined.dto.ts +++ b/api/src/ticket/dto/combined.dto.ts @@ -1,8 +1,11 @@ import { IntersectionType } from '@nestjs/swagger'; -import { Ticket } from './ticket.dto'; -import { User } from 'src/user/dto/user.dto'; -import { Device } from './device.dto'; +import { TicketDTO } from './ticket.dto'; +import { UserDTO } from 'src/user/dto/user.dto'; +import { DeviceDTO } from './device.dto'; -class TicketAndDevice extends IntersectionType(Ticket, Device) {} +class TicketAndDeviceDTO extends IntersectionType(TicketDTO, DeviceDTO) {} -export class Combined extends IntersectionType(TicketAndDevice, User) {} +export class CombinedDTO extends IntersectionType( + TicketAndDeviceDTO, + UserDTO, +) {} diff --git a/api/src/ticket/dto/create-combined.dto.ts b/api/src/ticket/dto/create-combined.dto.ts index 2abca50..c4a5807 100644 --- a/api/src/ticket/dto/create-combined.dto.ts +++ b/api/src/ticket/dto/create-combined.dto.ts @@ -1,14 +1,14 @@ import { IntersectionType, OmitType as Omit } from '@nestjs/swagger'; -import { CreateUser } from 'src/user/dto/create-user.dto'; -import { CreateTicket } from './create-ticket.dto'; -import { CreateDevice } from './create-device.dto'; +import { CreateUserDTO } from 'src/user/dto/create-user.dto'; +import { CreateTicketDTO } from './create-ticket.dto'; +import { CreateDeviceDTO } from './create-device.dto'; -class createTicketAndDevice extends IntersectionType( - CreateTicket, - Omit(CreateDevice, ['ticket_id']), +class createTicketAndDeviceDTO extends IntersectionType( + CreateTicketDTO, + Omit(CreateDeviceDTO, ['ticket_id']), ) {} -export class CreateCombined extends IntersectionType( - createTicketAndDevice, - Omit(CreateUser, ['admin']), +export class CreateCombinedDTO extends IntersectionType( + createTicketAndDeviceDTO, + Omit(CreateUserDTO, ['admin']), ) {} diff --git a/api/src/ticket/dto/create-device.dto.ts b/api/src/ticket/dto/create-device.dto.ts index 490c3f0..ee9b3ea 100644 --- a/api/src/ticket/dto/create-device.dto.ts +++ b/api/src/ticket/dto/create-device.dto.ts @@ -1,4 +1,4 @@ import { OmitType as Omit } from '@nestjs/swagger'; -import { Device } from './device.dto'; +import { DeviceDTO } from './device.dto'; -export class CreateDevice extends Omit(Device, ['device_id']) {} +export class CreateDeviceDTO extends Omit(DeviceDTO, ['device_id']) {} diff --git a/api/src/ticket/dto/create-ticket.dto.ts b/api/src/ticket/dto/create-ticket.dto.ts index 291f253..a8adb5f 100644 --- a/api/src/ticket/dto/create-ticket.dto.ts +++ b/api/src/ticket/dto/create-ticket.dto.ts @@ -1,7 +1,7 @@ -import { Ticket } from './ticket.dto'; +import { TicketDTO } from './ticket.dto'; import { OmitType as Omit } from '@nestjs/swagger'; -export class CreateTicket extends Omit(Ticket, [ +export class CreateTicketDTO extends Omit(TicketDTO, [ 'ticket_id', 'status', 'submission_date', diff --git a/api/src/ticket/dto/device.dto.ts b/api/src/ticket/dto/device.dto.ts index fcba3f0..022de62 100644 --- a/api/src/ticket/dto/device.dto.ts +++ b/api/src/ticket/dto/device.dto.ts @@ -1,6 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; -export class Device { +export class DeviceDTO { @ApiProperty({ description: 'id of device', example: 1 }) device_id: number; diff --git a/api/src/ticket/dto/ticket.dto.ts b/api/src/ticket/dto/ticket.dto.ts index a62c001..4d5fd08 100644 --- a/api/src/ticket/dto/ticket.dto.ts +++ b/api/src/ticket/dto/ticket.dto.ts @@ -6,7 +6,7 @@ export enum TicketType { 'ANY', } -export class Ticket { +export class TicketDTO { @ApiProperty({ readOnly: true }) ticket_id: number; diff --git a/api/src/ticket/dto/update-ticket.dto.ts b/api/src/ticket/dto/update-ticket.dto.ts index 8db254a..0da1bdd 100644 --- a/api/src/ticket/dto/update-ticket.dto.ts +++ b/api/src/ticket/dto/update-ticket.dto.ts @@ -1,9 +1,9 @@ import { PartialType } from '@nestjs/swagger'; -import { CreateTicket } from './create-ticket.dto'; -import { Ticket } from './ticket.dto'; +import { CreateTicketDTO } from './create-ticket.dto'; +import { TicketDTO } from './ticket.dto'; import { OmitType as Omit } from '@nestjs/swagger'; -export class UpdateTicketDto extends Omit(Ticket, [ +export class UpdateTicketDto extends Omit(TicketDTO, [ 'ticket_id', 'submission_date', 'lsu_id', diff --git a/api/src/ticket/ticket.controller.ts b/api/src/ticket/ticket.controller.ts index 5ce4f9a..a93d7f6 100644 --- a/api/src/ticket/ticket.controller.ts +++ b/api/src/ticket/ticket.controller.ts @@ -8,7 +8,7 @@ import { Put, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; -import { CreateCombined } from './dto/create-combined.dto'; +import { CreateCombinedDTO } from './dto/create-combined.dto'; import { TicketType } from './dto/ticket.dto'; import { UpdateTicketDto } from './dto/update-ticket.dto'; import { TicketService } from './ticket.service'; @@ -20,19 +20,19 @@ export class TicketController { /* WORKING Implementation */ @Post() - create(@Body() createCombined: CreateCombined) { + create(@Body() createCombinedDTO: CreateCombinedDTO) { Logger.log( { req: { http: 'POST /api/ticket', params: 'none', - body: createCombined, + body: createCombinedDTO, }, }, 'TicketController.create', false, ); - return this.ticketService.create(createCombined); + return this.ticketService.create(createCombinedDTO); } /* WORKING Implementation */ diff --git a/api/src/ticket/ticket.service.ts b/api/src/ticket/ticket.service.ts index b73ba0b..b63aed3 100644 --- a/api/src/ticket/ticket.service.ts +++ b/api/src/ticket/ticket.service.ts @@ -7,14 +7,14 @@ import { } from '@nestjs/common'; import { Pool, QueryConfig } from 'pg'; import { PG_CONNECTION } from 'src/connection'; -import { CreateUser } from 'src/user/dto/create-user.dto'; -import { User } from 'src/user/dto/user.dto'; -import { Combined } from './dto/combined.dto'; -import { CreateCombined } from './dto/create-combined.dto'; -import { CreateDevice } from './dto/create-device.dto'; -import { CreateTicket } from './dto/create-ticket.dto'; -import { Device } from './dto/device.dto'; -import { Ticket, TicketType } from './dto/ticket.dto'; +import { CreateUserDTO } from 'src/user/dto/create-user.dto'; +import { UserDTO } from 'src/user/dto/user.dto'; +import { CombinedDTO } from './dto/combined.dto'; +import { CreateCombinedDTO } from './dto/create-combined.dto'; +import { CreateDeviceDTO } from './dto/create-device.dto'; +import { CreateTicketDTO } from './dto/create-ticket.dto'; +import { DeviceDTO } from './dto/device.dto'; +import { TicketDTO, TicketType } from './dto/ticket.dto'; import { UpdateTicketDto } from './dto/update-ticket.dto'; @Injectable() @@ -24,10 +24,10 @@ export class TicketService { /** * Queries and inserts user if user does not exists * - * @param createUser + * @param createUserDTO * @returns User */ - private async createUser(createUser: CreateUser) { + private async createUser(createUserDTO: CreateUserDTO) { const { lsu_id, email, @@ -36,7 +36,7 @@ export class TicketService { phone_number, department, admin, - } = createUser; + } = createUserDTO; /* Check to see if user exists */ const findQuery: QueryConfig = { @@ -46,7 +46,7 @@ export class TicketService { }; try { - const res = await this.connection.query(findQuery); + const res = await this.connection.query(findQuery); /* If user exists abort insert operation by returning early */ if (res.rows.length > 0) { @@ -79,7 +79,7 @@ export class TicketService { ], }; try { - const res = await this.connection.query(insertQuery); + const res = await this.connection.query(insertQuery); /* Return newly inserted user */ return res.rows[0]; @@ -97,17 +97,17 @@ export class TicketService { /** * Inserts ticket into ticket table * - * @param createTicket + * @param createTicketDTO * @returns Ticket */ - private async createTicket(createTicket: CreateTicket) { + private async createTicket(createTicketDTO: CreateTicketDTO) { const { lsu_id, core_issue, description, problem_category, priority, - } = createTicket; + } = createTicketDTO; /* Status set to open for new ticket */ const status = 'OPEN'; @@ -132,7 +132,7 @@ export class TicketService { }; try { - const res = await this.connection.query(query); + const res = await this.connection.query(query); /* Return newly inserted ticket */ return res.rows[0]; @@ -149,17 +149,17 @@ export class TicketService { /** * Inserts new device into device table - * @param createDevice + * @param createDeviceDTO * @returns Device */ - private async createDevice(createDevice: CreateDevice) { + private async createDevice(createDeviceDTO: CreateDeviceDTO) { const { ticket_id, manufacturer, model, operating_system, operating_system_version, - } = createDevice; + } = createDeviceDTO; /* Insert Device into db */ const query: QueryConfig = { @@ -175,7 +175,7 @@ export class TicketService { ], }; try { - const res = await this.connection.query(query); + const res = await this.connection.query(query); /* Return newly inserted device */ return res.rows[0]; @@ -214,16 +214,16 @@ export class TicketService { } /* WORKING Implementation */ - async create(createCombined: CreateCombined) { + async create(createCombinedDTO: CreateCombinedDTO) { /* Response Accumulator */ - let response: Combined; + let response: CombinedDTO; - let device: Device; - let ticket: Ticket; - let user: User; + let device: DeviceDTO; + let ticket: TicketDTO; + let user: UserDTO; /* Insert or Retrieve User */ - const createUser: CreateUser = { ...createCombined, admin: false }; // tickets are created by students so admin is false + const createUser: CreateUserDTO = { ...createCombinedDTO, admin: false }; // tickets are created by students so admin is false try { user = await this.createUser(createUser); @@ -235,7 +235,7 @@ export class TicketService { } /* Create new Ticket */ - const createTicket: CreateTicket = { ...createCombined }; + const createTicket: CreateTicketDTO = { ...createCombinedDTO }; try { ticket = await this.createTicket(createTicket); @@ -247,8 +247,8 @@ export class TicketService { } /* Create new Device */ - const createDevice: CreateDevice = { - ...createCombined, + const createDevice: CreateDeviceDTO = { + ...createCombinedDTO, ticket_id: ticket.ticket_id, }; try { @@ -301,7 +301,7 @@ export class TicketService { break; } try { - const queryRes = await this.connection.query(query); + const queryRes = await this.connection.query(query); /* If no tickets return empty array */ if (queryRes.rows.length === 0) { @@ -322,20 +322,21 @@ export class TicketService { /* WORKING implementation */ async findOne(ticket_id: number) { + /* Query ticket by ticket_id */ const query: QueryConfig = { name: 'select_ticket_by_ticket_id', text: 'SELECT * FROM ticket WHERE ticket_id = $1', values: [ticket_id], }; try { - const queryRes = await this.connection.query(query); + const res = await this.connection.query(query); /* If no ticket found return empty object*/ - if (queryRes.rows.length === 0) { + if (res.rows.length === 0) { return {}; } - return queryRes.rows[0]; + return res.rows[0]; } catch (error) { throw new HttpException( { @@ -364,7 +365,7 @@ export class TicketService { values: [ticket_id], }; try { - const res = await this.connection.query(findQuery); + const res = await this.connection.query(findQuery); /* If no ticket found throw custom error*/ if (res.rows.length < 1) { diff --git a/api/src/user/dto/create-user.dto.ts b/api/src/user/dto/create-user.dto.ts index 9190090..3ed9592 100644 --- a/api/src/user/dto/create-user.dto.ts +++ b/api/src/user/dto/create-user.dto.ts @@ -1,3 +1,3 @@ -import { User } from './user.dto'; +import { UserDTO } from './user.dto'; -export class CreateUser extends User {} +export class CreateUserDTO extends UserDTO {} diff --git a/api/src/user/dto/update-user.dto.ts b/api/src/user/dto/update-user.dto.ts index 4f57edf..f4c017e 100644 --- a/api/src/user/dto/update-user.dto.ts +++ b/api/src/user/dto/update-user.dto.ts @@ -1,3 +1,3 @@ -import { User } from './user.dto'; +import { UserDTO } from './user.dto'; -export class UpdateUser extends User {} +export class UpdateUserDTO extends UserDTO {} diff --git a/api/src/user/dto/user.dto.ts b/api/src/user/dto/user.dto.ts index 6701000..8d43540 100644 --- a/api/src/user/dto/user.dto.ts +++ b/api/src/user/dto/user.dto.ts @@ -4,7 +4,7 @@ export enum UserType { 'STUDENT', 'USER', } -export class User { +export class UserDTO { @ApiProperty({ minLength: 9, maxLength: 9, diff --git a/api/src/user/user.controller.ts b/api/src/user/user.controller.ts index de3f6bd..0a5bfda 100644 --- a/api/src/user/user.controller.ts +++ b/api/src/user/user.controller.ts @@ -8,10 +8,10 @@ import { Delete, } from '@nestjs/common'; import { UserService } from './user.service'; -import { CreateUser } from './dto/create-user.dto'; +import { CreateUserDTO } from './dto/create-user.dto'; import { UserType } from './dto/user.dto'; import { ApiTags } from '@nestjs/swagger'; -import { UpdateUser } from './dto/update-user.dto'; +import { UpdateUserDTO } from './dto/update-user.dto'; @ApiTags('user') @Controller('/api/user') @@ -19,7 +19,7 @@ export class UserController { constructor(private readonly userService: UserService) {} /* WORKING implementation */ @Post() - async create(@Body() createUserDto: CreateUser) { + async create(@Body() createUserDto: CreateUserDTO) { return await this.userService.create(createUserDto); } /* WORKING implementation */ @@ -48,7 +48,10 @@ export class UserController { /* WORKING implementation */ @Put(':lsu_id') - update(@Body() updateUser: UpdateUser, @Param('lsu_id') lsu_id: number) { - return this.userService.update(updateUser, lsu_id); + update( + @Param('lsu_id') lsu_id: number, + @Body() updateUserDTO: UpdateUserDTO, + ) { + return this.userService.update(lsu_id, updateUserDTO); } } diff --git a/api/src/user/user.service.ts b/api/src/user/user.service.ts index 8577e09..a7d7ad5 100644 --- a/api/src/user/user.service.ts +++ b/api/src/user/user.service.ts @@ -7,16 +7,16 @@ import { } from '@nestjs/common'; import { Pool, QueryConfig } from 'pg'; import { PG_CONNECTION } from 'src/connection'; -import { CreateUser } from './dto/create-user.dto'; -import { UpdateUser } from './dto/update-user.dto'; -import { User, UserType } from './dto/user.dto'; +import { CreateUserDTO } from './dto/create-user.dto'; +import { UpdateUserDTO } from './dto/update-user.dto'; +import { UserDTO, UserType } from './dto/user.dto'; @Injectable() export class UserService { constructor(@Inject(PG_CONNECTION) private connection: Pool) {} /* WORKING implementation */ - async create(createUser: CreateUser) { + async create(createUserDTO: CreateUserDTO) { const { lsu_id, email, @@ -25,7 +25,7 @@ export class UserService { phone_number, department, admin, - } = createUser; + } = createUserDTO; const findQuery: QueryConfig = { name: 'select_user_by_id_or_email', @@ -80,7 +80,7 @@ export class UserService { ], }; try { - const res = await this.connection.query(insertQuery); + const res = await this.connection.query(insertQuery); return res.rows[0]; } catch (error) { throw new HttpException( @@ -114,7 +114,7 @@ export class UserService { } try { - const queryRes = await this.connection.query(query); + const queryRes = await this.connection.query(query); /* If no users found return empty array */ if (queryRes.rows.length < 1) { return []; @@ -137,7 +137,7 @@ export class UserService { text: 'SELECT * FROM "user" WHERE "lsu_id" = $1', }; try { - const queryRes = await this.connection.query(query, [lsu_id]); + const queryRes = await this.connection.query(query, [lsu_id]); /* If customer not found return empty object */ if (queryRes.rows.length < 1) { return {}; @@ -156,7 +156,7 @@ export class UserService { } /* WORKING implementation */ - async update(updateUser: UpdateUser, old_lsu_id: number) { + async update(old_lsu_id: number, updateUserDTO: UpdateUserDTO) { const { lsu_id, email, @@ -165,8 +165,9 @@ export class UserService { phone_number, department, admin, - } = updateUser; + } = updateUserDTO; + /* Find user by old_lsu_id supplied in route i.e. /api/user/{lsu_id} */ const findQuery: QueryConfig = { name: 'select_user_by_id', text: 'SELECT lsu_id FROM "user" WHERE lsu_id = $1', @@ -175,7 +176,7 @@ export class UserService { try { const res = await this.connection.query(findQuery); - /* Test to see if student exists */ + /* Test to see if user exists */ if (res.rows.length < 1) { /*Throw custom error to be handled in catch*/ throw new Error('BAD_REQUEST'); @@ -220,7 +221,7 @@ export class UserService { ], }; try { - const res = await this.connection.query(updateQuery); + const res = await this.connection.query(updateQuery); return res.rows[0]; } catch (error) { throw new HttpException( From 448eef3e60e86e2d110a8d235eb0591753bb653c Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 17:24:50 -0600 Subject: [PATCH 07/13] refactored TicketAssign -> Assignment --- api/src/app.module.ts | 4 ++-- api/src/assign/ticketassign.module.ts | 11 ----------- .../assignment.controller.ts} | 14 +++++++------- api/src/assignment/assignment.module..ts | 11 +++++++++++ .../assignment.service.ts} | 19 +++++++------------ .../dto/assignment.dto.ts} | 2 +- .../dto/create-assignment.dto.ts} | 2 +- .../dto/update-assignment.dto.ts} | 2 +- 8 files changed, 30 insertions(+), 35 deletions(-) delete mode 100644 api/src/assign/ticketassign.module.ts rename api/src/{assign/ticketassign.controller.ts => assignment/assignment.controller.ts} (63%) create mode 100644 api/src/assignment/assignment.module..ts rename api/src/{assign/ticketassign.service.ts => assignment/assignment.service.ts} (73%) rename api/src/{assign/entities/ticketassign.entity.ts => assignment/dto/assignment.dto.ts} (74%) rename api/src/{assign/dto/create-ticketassign.dto.ts => assignment/dto/create-assignment.dto.ts} (86%) rename api/src/{assign/dto/update-ticketassign.dto.ts => assignment/dto/update-assignment.dto.ts} (70%) diff --git a/api/src/app.module.ts b/api/src/app.module.ts index 837029a..49dab65 100644 --- a/api/src/app.module.ts +++ b/api/src/app.module.ts @@ -5,7 +5,7 @@ import { AppController } from './app.controller'; import { AppService } from './app.service'; import { TicketModule } from './ticket/ticket.module'; import { TicketWorkModule } from './work/ticketwork.module'; -import { TicketAssignModule } from './assign/ticketassign.module'; +import { AssignmentModule } from './assignment/assignment.module.'; import { UserModule } from './user/uer.module'; /** @@ -41,7 +41,7 @@ const configImports = (modules: ModuleMetadata['imports']) => { imports: configImports([ TicketModule, TicketWorkModule, - TicketAssignModule, + AssignmentModule, UserModule, ]), controllers: [AppController], diff --git a/api/src/assign/ticketassign.module.ts b/api/src/assign/ticketassign.module.ts deleted file mode 100644 index 877b897..0000000 --- a/api/src/assign/ticketassign.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TicketAssignService } from './ticketassign.service'; -import { TicketAssignController } from './ticketassign.controller'; -import { DbModule } from 'src/db/db.module'; - -@Module({ - imports:[DbModule], - controllers: [TicketAssignController], - providers: [TicketAssignService] -}) -export class TicketAssignModule {} diff --git a/api/src/assign/ticketassign.controller.ts b/api/src/assignment/assignment.controller.ts similarity index 63% rename from api/src/assign/ticketassign.controller.ts rename to api/src/assignment/assignment.controller.ts index 26a93e5..1cc3cbc 100644 --- a/api/src/assign/ticketassign.controller.ts +++ b/api/src/assignment/assignment.controller.ts @@ -7,18 +7,18 @@ import { Param, Delete, } from '@nestjs/common'; -import { TicketAssignService } from './ticketassign.service'; -import { CreateTicketAssignDto } from './dto/create-ticketassign.dto'; -import { UpdateTicketAssignDto } from './dto/update-ticketassign.dto'; +import { AssignmentService } from './assignment.service'; +import { CreateAssignmentDTO } from './dto/create-assignment.dto'; +import { UpdateAssignmentDTO } from './dto/update-assignment.dto'; import { ApiTags } from '@nestjs/swagger'; @ApiTags('ticket') @Controller('/api/ticket/assign') -export class TicketAssignController { - constructor(private readonly ticketAssignService: TicketAssignService) {} +export class AssignmentController { + constructor(private readonly ticketAssignService: AssignmentService) {} /* Working Implementation */ @Post() - async create(@Body() createTicketAssignDto: CreateTicketAssignDto) { + async create(@Body() createTicketAssignDto: CreateAssignmentDTO) { return await this.ticketAssignService.create(createTicketAssignDto); } /* TODO */ @@ -35,7 +35,7 @@ export class TicketAssignController { @Put(':id') update( @Param('id') id: string, - @Body() updateTicketAssignDto: UpdateTicketAssignDto, + @Body() updateTicketAssignDto: UpdateAssignmentDTO, ) { return this.ticketAssignService.update(+id, updateTicketAssignDto); } diff --git a/api/src/assignment/assignment.module..ts b/api/src/assignment/assignment.module..ts new file mode 100644 index 0000000..ffe4a42 --- /dev/null +++ b/api/src/assignment/assignment.module..ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { AssignmentService } from './assignment.service'; +import { AssignmentController } from './assignment.controller'; +import { DbModule } from 'src/db/db.module'; + +@Module({ + imports: [DbModule], + controllers: [AssignmentController], + providers: [AssignmentService], +}) +export class AssignmentModule {} diff --git a/api/src/assign/ticketassign.service.ts b/api/src/assignment/assignment.service.ts similarity index 73% rename from api/src/assign/ticketassign.service.ts rename to api/src/assignment/assignment.service.ts index 29f3ea4..08f78ec 100644 --- a/api/src/assign/ticketassign.service.ts +++ b/api/src/assignment/assignment.service.ts @@ -1,25 +1,20 @@ import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; import { Pool } from 'pg'; import { PG_CONNECTION } from 'src/connection'; -import { CreateTicketAssignDto } from './dto/create-ticketassign.dto'; -import { UpdateTicketAssignDto } from './dto/update-ticketassign.dto'; -import { TicketAssign } from './entities/ticketassign.entity'; +import { CreateAssignmentDTO } from './dto/create-assignment.dto'; +import { UpdateAssignmentDTO } from './dto/update-assignment.dto'; +import { AssignmentDTO } from './dto/assignment.dto'; /* TODO: - Implement remaining methods - Find solution to abstract SQL */ @Injectable() -export class TicketAssignService { +export class AssignmentService { constructor(@Inject(PG_CONNECTION) private connection: Pool) {} - async create(createTicketAssignDto: CreateTicketAssignDto) { - const { - assignedby, - assignedto, - comment, - assigndate, - } = createTicketAssignDto; + async create(createAssignmentDTO: CreateAssignmentDTO) { + const { assignedby, assignedto, comment, assigndate } = createAssignmentDTO; /* Insert new user into db TODO: implement error handling for pg request @@ -47,7 +42,7 @@ export class TicketAssignService { return `This action returns a #${id} user`; } /* TODO */ - update(id: number, updateTicketAssignDto: UpdateTicketAssignDto) { + update(id: number, updateAssignmentDTO: UpdateAssignmentDTO) { return `This action updates a #${id} user`; } /* TODO */ diff --git a/api/src/assign/entities/ticketassign.entity.ts b/api/src/assignment/dto/assignment.dto.ts similarity index 74% rename from api/src/assign/entities/ticketassign.entity.ts rename to api/src/assignment/dto/assignment.dto.ts index 49fb52b..678b507 100644 --- a/api/src/assign/entities/ticketassign.entity.ts +++ b/api/src/assignment/dto/assignment.dto.ts @@ -1,4 +1,4 @@ -export class TicketAssign { +export class AssignmentDTO { assignedby: string; assignedto: string; comment: string; diff --git a/api/src/assign/dto/create-ticketassign.dto.ts b/api/src/assignment/dto/create-assignment.dto.ts similarity index 86% rename from api/src/assign/dto/create-ticketassign.dto.ts rename to api/src/assignment/dto/create-assignment.dto.ts index ff9feb5..d834e94 100644 --- a/api/src/assign/dto/create-ticketassign.dto.ts +++ b/api/src/assignment/dto/create-assignment.dto.ts @@ -1,6 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; -export class CreateTicketAssignDto { +export class CreateAssignmentDTO { @ApiProperty({ minLength: 3 }) assignedby: string; diff --git a/api/src/assign/dto/update-ticketassign.dto.ts b/api/src/assignment/dto/update-assignment.dto.ts similarity index 70% rename from api/src/assign/dto/update-ticketassign.dto.ts rename to api/src/assignment/dto/update-assignment.dto.ts index 07b8fee..5e601a8 100644 --- a/api/src/assign/dto/update-ticketassign.dto.ts +++ b/api/src/assignment/dto/update-assignment.dto.ts @@ -1,4 +1,4 @@ -export class UpdateTicketAssignDto { +export class UpdateAssignmentDTO { assignedby: string; assignedto: string; comment: string; From b0a0c4257e96ec6ada5e5fb286ca0eb2d14b9c46 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 18:09:29 -0600 Subject: [PATCH 08/13] extracted date util to util.ts --- api/src/ticket/ticket.service.ts | 26 ++------------------------ api/src/util.ts | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) create mode 100644 api/src/util.ts diff --git a/api/src/ticket/ticket.service.ts b/api/src/ticket/ticket.service.ts index b63aed3..ca257b3 100644 --- a/api/src/ticket/ticket.service.ts +++ b/api/src/ticket/ticket.service.ts @@ -16,6 +16,7 @@ import { CreateTicketDTO } from './dto/create-ticket.dto'; import { DeviceDTO } from './dto/device.dto'; import { TicketDTO, TicketType } from './dto/ticket.dto'; import { UpdateTicketDto } from './dto/update-ticket.dto'; +import { createDate } from 'src/util'; @Injectable() export class TicketService { @@ -113,7 +114,7 @@ export class TicketService { const status = 'OPEN'; /* Submission date set to current server time */ - const submission_date = this.createDate(); + const submission_date = createDate(); /* Insert new ticket into db */ const query: QueryConfig = { @@ -190,29 +191,6 @@ export class TicketService { } } - /** - * Helper method for createTicket to get current date in SQL format - * - * @author KooiInc - * (https://stackoverflow.com/users/58186/kooiinc) - * - * @adapted from https://stackoverflow.com/questions/10632346/how-to-format-a-date-in-mm-dd-yyyy-hhmmss-format-in-javascript - * @returns Date (YYYY-MM-DD HH:MM:SS) - */ - private createDate() { - //@ts-ignore - Number.prototype.padLeft = function (base, chr) { - var len = String(base || 10).length - String(this).length + 1; - return len > 0 ? new Array(len).join(chr || '0') + this : this; - }; - const d = new Date(Date.now()); - const date = - [d.getFullYear(), d.getMonth() + 1, d.getDate()].join('-') + - ' ' + - [d.getHours(), d.getMinutes(), d.getSeconds()].join(':'); - return date; - } - /* WORKING Implementation */ async create(createCombinedDTO: CreateCombinedDTO) { /* Response Accumulator */ diff --git a/api/src/util.ts b/api/src/util.ts new file mode 100644 index 0000000..1150951 --- /dev/null +++ b/api/src/util.ts @@ -0,0 +1,22 @@ +/** + * Helper method for createTicket to get current date in SQL format + * + * @author KooiInc + * (https://stackoverflow.com/users/58186/kooiinc) + * + * @adapted from https://stackoverflow.com/questions/10632346/how-to-format-a-date-in-mm-dd-yyyy-hhmmss-format-in-javascript + * @returns Date (YYYY-MM-DD HH:MM:SS) + */ +export const createDate = () => { + //@ts-ignore + Number.prototype.padLeft = function (base, chr) { + var len = String(base || 10).length - String(this).length + 1; + return len > 0 ? new Array(len).join(chr || '0') + this : this; + }; + const d = new Date(Date.now()); + const date = + [d.getFullYear(), d.getMonth() + 1, d.getDate()].join('-') + + ' ' + + [d.getHours(), d.getMinutes(), d.getSeconds()].join(':'); + return date; +}; From 9d54cc11048a3bad07ceaeebfc8416e208cea472 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 18:09:59 -0600 Subject: [PATCH 09/13] implemented assignment endpoints --- api/src/assignment/assignment.controller.ts | 62 ++++---- api/src/assignment/assignment.service.ts | 153 ++++++++++++++++---- 2 files changed, 151 insertions(+), 64 deletions(-) diff --git a/api/src/assignment/assignment.controller.ts b/api/src/assignment/assignment.controller.ts index 1cc3cbc..00d2b80 100644 --- a/api/src/assignment/assignment.controller.ts +++ b/api/src/assignment/assignment.controller.ts @@ -1,47 +1,45 @@ -import { - Controller, - Get, - Post, - Body, - Put, - Param, - Delete, -} from '@nestjs/common'; +import { Body, Controller, Get, Param, Post } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; import { AssignmentService } from './assignment.service'; +import { AssignmentType } from './dto/assignment.dto'; import { CreateAssignmentDTO } from './dto/create-assignment.dto'; -import { UpdateAssignmentDTO } from './dto/update-assignment.dto'; -import { ApiTags } from '@nestjs/swagger'; -@ApiTags('ticket') -@Controller('/api/ticket/assign') +@ApiTags('assignment') +@Controller('/api/assign') export class AssignmentController { constructor(private readonly ticketAssignService: AssignmentService) {} - /* Working Implementation */ + + /* WORKING Implementation */ + /* TODO: fix date formatting */ @Post() - async create(@Body() createTicketAssignDto: CreateAssignmentDTO) { - return await this.ticketAssignService.create(createTicketAssignDto); + async create(@Body() createAssignmentDTO: CreateAssignmentDTO) { + return await this.ticketAssignService.create(createAssignmentDTO); } - /* TODO */ + + /* WORKING Implementation */ @Get() findAll() { return this.ticketAssignService.findAll(); } - /* TODO */ - @Get(':id') - findOne(@Param('id') id: string) { - return this.ticketAssignService.findOne(+id); + + /* WORKING Implementation */ + @Get('user/:lsu_id') + findAllByLsuId(@Param('lsu_id') lsu_id: number) { + return this.ticketAssignService.findAllById(AssignmentType.LSU_ID, lsu_id); } - /* TODO */ - @Put(':id') - update( - @Param('id') id: string, - @Body() updateTicketAssignDto: UpdateAssignmentDTO, - ) { - return this.ticketAssignService.update(+id, updateTicketAssignDto); + + /* WORKING Implementation */ + @Get('ticket/:ticket_id') + findAllByTicketId(@Param('ticket_id') ticket_id: number) { + return this.ticketAssignService.findAllById( + AssignmentType.TICKET_ID, + ticket_id, + ); } - /* TODO */ - @Delete(':id') - remove(@Param('id') id: string) { - return this.ticketAssignService.remove(+id); + + /* WORKING Implementation */ + @Get(':assignment_id') + findOne(@Param('assignment_id') assignment_id: string) { + return this.ticketAssignService.findOne(+assignment_id); } } diff --git a/api/src/assignment/assignment.service.ts b/api/src/assignment/assignment.service.ts index 08f78ec..97d9b8b 100644 --- a/api/src/assignment/assignment.service.ts +++ b/api/src/assignment/assignment.service.ts @@ -1,9 +1,9 @@ import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; -import { Pool } from 'pg'; +import { Pool, Query, QueryConfig } from 'pg'; import { PG_CONNECTION } from 'src/connection'; import { CreateAssignmentDTO } from './dto/create-assignment.dto'; -import { UpdateAssignmentDTO } from './dto/update-assignment.dto'; -import { AssignmentDTO } from './dto/assignment.dto'; +import { AssignmentDTO, AssignmentType } from './dto/assignment.dto'; +import { createDate } from 'src/util'; /* TODO: - Implement remaining methods @@ -14,39 +14,128 @@ export class AssignmentService { constructor(@Inject(PG_CONNECTION) private connection: Pool) {} async create(createAssignmentDTO: CreateAssignmentDTO) { - const { assignedby, assignedto, comment, assigndate } = createAssignmentDTO; - - /* Insert new user into db - TODO: implement error handling for pg request - */ - const text = - 'INSERT INTO ticketwork(assignedby, assignedto, comment, assigndate) VALUES ($1, $2, $3, $4) RETURNING *'; - const values = [assignedby, assignedto, comment, assigndate]; - const res = (await this.connection.query(text, values)) - .rows[0]; - - /* Return user object without password */ - const ticketassign = new TicketAssign(); - ticketassign.assignedby = res.assignedby; - ticketassign.assignedto = res.assignedto; - ticketassign.comment = res.comment; - ticketassign.assigndate = res.assigndate; - return ticketassign; - } - /* TODO */ - findAll() { - return `This action returns all user`; + const { lsu_id, ticket_id } = createAssignmentDTO; + const assigned_date = createDate(); + + /* Insert new assignment into db */ + const query: QueryConfig = { + name: 'insert_assignment', + text: + 'INSERT INTO assignment(lsu_id, ticket_id, assigned_date) VALUES ($1, $2, $3) RETURNING *', + values: [lsu_id, ticket_id, assigned_date], + }; + try { + const res = await this.connection.query(query); + + /* Return newly inserted assignment */ + return res.rows[0]; + } catch (error) { + throw new HttpException( + { + query: query, + error: error, + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } } /* TODO */ - findOne(id: number) { - return `This action returns a #${id} user`; + async findAllById(type: AssignmentType, id: number) { + let query: QueryConfig; + switch (type) { + case AssignmentType.LSU_ID: + query = { + name: 'select_all_assignment_by_lsu_id', + text: 'SELECT * FROM assignment WHERE lsu_id = $1', + values: [id], + }; + break; + case AssignmentType.TICKET_ID: + query = { + name: 'select_all_assignment_by_ticket_id', + text: 'SELECT * FROM assignment WHERE ticket_id = $1', + values: [id], + }; + break; + + default: + /* default error caused by not using controller properly */ + throw new HttpException( + { + error: + 'Switch statment in assignment.service.findAllById somehow failed', + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + try { + const res = await this.connection.query(query); + + /* If none exist, return empty array */ + if (res.rows.length < 1) { + return []; + } + /* return array of Assignment objects */ + return res.rows; + } catch (error) { + throw new HttpException( + { + query: query, + error: error, + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } } - /* TODO */ - update(id: number, updateAssignmentDTO: UpdateAssignmentDTO) { - return `This action updates a #${id} user`; + + async findAll() { + const query: QueryConfig = { + name: 'select_all_assignment', + text: 'SELECT * FROM assignment', + }; + try { + const res = await this.connection.query(query); + + /* If none exist, return empty array */ + if (res.rows.length < 1) { + return []; + } + /* return array of Assignment objects */ + return res.rows; + } catch (error) { + throw new HttpException( + { + query: query, + error: error, + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } } /* TODO */ - remove(id: number) { - return `This action removes a #${id} user`; + async findOne(assignment_id: number) { + const query: QueryConfig = { + name: 'select_assignment_by_assignment_id', + text: 'SELECT * FROM assignment WHERE assignment_id = $1', + values: [assignment_id], + }; + try { + const res = await this.connection.query(query); + + /* If none exist, return empty object */ + if (res.rows.length < 1) { + return {}; + } + /* return Assignment object */ + return res.rows[0]; + } catch (error) { + throw new HttpException( + { + query: query, + error: error, + }, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } } } From 074c36a283343c6d3f03686d1f6cecbcabc32980 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 18:10:23 -0600 Subject: [PATCH 10/13] removed unused dto --- api/src/assignment/dto/update-assignment.dto.ts | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 api/src/assignment/dto/update-assignment.dto.ts diff --git a/api/src/assignment/dto/update-assignment.dto.ts b/api/src/assignment/dto/update-assignment.dto.ts deleted file mode 100644 index 5e601a8..0000000 --- a/api/src/assignment/dto/update-assignment.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -export class UpdateAssignmentDTO { - assignedby: string; - assignedto: string; - comment: string; - assigndate: string; -} From 6ff2e8fd85ba0bf1f87079c61dc306224600ae55 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 18:10:42 -0600 Subject: [PATCH 11/13] updated dtos --- api/src/assignment/dto/assignment.dto.ts | 34 ++++++++++++++++--- .../assignment/dto/create-assignment.dto.ts | 20 ++++------- api/src/ticket/dto/ticket.dto.ts | 1 + 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/api/src/assignment/dto/assignment.dto.ts b/api/src/assignment/dto/assignment.dto.ts index 678b507..fcd42c4 100644 --- a/api/src/assignment/dto/assignment.dto.ts +++ b/api/src/assignment/dto/assignment.dto.ts @@ -1,6 +1,32 @@ +import { ApiProperty } from '@nestjs/swagger'; +export enum AssignmentType { + 'LSU_ID', + 'TICKET_ID', +} export class AssignmentDTO { - assignedby: string; - assignedto: string; - comment: string; - assigndate: Date; + @ApiProperty({ + description: 'serial generated assignment id', + example: 1, + }) + assignment_id: number; + + @ApiProperty({ + minLength: 9, + maxLength: 9, + description: '9-digit number starting with 89', + example: 897584512, + }) + lsu_id: number; + + @ApiProperty({ + description: 'serial generated ticket id', + example: 1, + }) + ticket_id: number; + + @ApiProperty({ + description: 'YYYY-MM-DD HH:MM:SS', + example: '2020-07-21 12:44:22', + }) + assigned_date: string; } diff --git a/api/src/assignment/dto/create-assignment.dto.ts b/api/src/assignment/dto/create-assignment.dto.ts index d834e94..533aeaa 100644 --- a/api/src/assignment/dto/create-assignment.dto.ts +++ b/api/src/assignment/dto/create-assignment.dto.ts @@ -1,15 +1,7 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, OmitType as Omit } from '@nestjs/swagger'; +import { AssignmentDTO } from './assignment.dto'; -export class CreateAssignmentDTO { - @ApiProperty({ minLength: 3 }) - assignedby: string; - - @ApiProperty({ minLength: 3 }) - assignedto: string; - - @ApiProperty({}) - comment: number; - - @ApiProperty({}) - assigndate: Date; -} +export class CreateAssignmentDTO extends Omit(AssignmentDTO, [ + 'assignment_id', + 'assigned_date', +]) {} diff --git a/api/src/ticket/dto/ticket.dto.ts b/api/src/ticket/dto/ticket.dto.ts index 4d5fd08..2048e6c 100644 --- a/api/src/ticket/dto/ticket.dto.ts +++ b/api/src/ticket/dto/ticket.dto.ts @@ -47,6 +47,7 @@ export class TicketDTO { @ApiProperty({ description: 'YYYY-MM-DD HH:MM:SS', + example: '2020-07-21 12:44:22', }) submission_date: string; } From 4eef1ab4ba451ed3cf8d2316e7ede25879a81835 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 18:18:43 -0600 Subject: [PATCH 12/13] updated README with current working endpoints --- api/README.md | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/api/README.md b/api/README.md index 67bc834..35c332e 100644 --- a/api/README.md +++ b/api/README.md @@ -164,9 +164,43 @@ req: body: {UpdateUserDTO} res: body: {UserDTO} ``` -## Assign +## Assignment -TODO +Get all assignments + +``` +GET /api/assignment +res: body: {AssignmentDTO} +``` + +Get all assignments assigned to admin by lsu_id + +``` +GET /api/assignment/user/{lsu_id} +res: body: {AssignmentDTO[]} +``` + +Get all assignments assigned to ticket by ticket_id + +``` +GET /api/assignment/ticket/{ticket_id} +res: body: {AssignmentDTO[]} +``` + +Get one assignment by assignment_id + +``` +GET /api/assignment/{assignment_id} +res: body: {AssignmentDTO} +``` + +Post new assignment + +``` +POST /api/assignment +req: body: {CreateAssignmentDTO} +res: body: {AssignmentDTO} +``` ## Work From c469f20e6fad891d0126a1ec753592028a4775fa Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 28 Nov 2020 18:19:02 -0600 Subject: [PATCH 13/13] updated schema --- schema.sql | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/schema.sql b/schema.sql index a269e65..376f41a 100644 --- a/schema.sql +++ b/schema.sql @@ -26,7 +26,8 @@ create table if not exists ticket status varchar(20) not null, problem_category varchar(50) not null, description varchar(500), - core_issue varchar(50) + core_issue varchar(50), + submission_date timestamp without time zone ); alter table ticket owner to brvuirrqqcjzsb; @@ -67,7 +68,9 @@ create table if not exists assignment ticket_id integer not null constraint assignment_ticket_ticket_id_fk references ticket - on update cascade on delete cascade + on update cascade on delete cascade, + assigned_date timestamp without time zone + ); alter table assignment owner to brvuirrqqcjzsb;