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 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/dto/create-ticketassign.dto.ts b/api/src/assign/dto/create-ticketassign.dto.ts deleted file mode 100644 index ff9feb5..0000000 --- a/api/src/assign/dto/create-ticketassign.dto.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; - -export class CreateTicketAssignDto { - @ApiProperty({ minLength: 3 }) - assignedby: string; - - @ApiProperty({ minLength: 3 }) - assignedto: string; - - @ApiProperty({}) - comment: number; - - @ApiProperty({}) - assigndate: Date; -} diff --git a/api/src/assign/dto/update-ticketassign.dto.ts b/api/src/assign/dto/update-ticketassign.dto.ts deleted file mode 100644 index 07b8fee..0000000 --- a/api/src/assign/dto/update-ticketassign.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -export class UpdateTicketAssignDto { - assignedby: string; - assignedto: string; - comment: string; - assigndate: string; -} diff --git a/api/src/assign/entities/ticketassign.entity.ts b/api/src/assign/entities/ticketassign.entity.ts deleted file mode 100644 index 49fb52b..0000000 --- a/api/src/assign/entities/ticketassign.entity.ts +++ /dev/null @@ -1,6 +0,0 @@ -export class TicketAssign { - assignedby: string; - assignedto: string; - comment: string; - assigndate: Date; -} diff --git a/api/src/assign/ticketassign.controller.ts b/api/src/assign/ticketassign.controller.ts deleted file mode 100644 index 26a93e5..0000000 --- a/api/src/assign/ticketassign.controller.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - Controller, - Get, - Post, - Body, - Put, - 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 { ApiTags } from '@nestjs/swagger'; - -@ApiTags('ticket') -@Controller('/api/ticket/assign') -export class TicketAssignController { - constructor(private readonly ticketAssignService: TicketAssignService) {} - /* Working Implementation */ - @Post() - async create(@Body() createTicketAssignDto: CreateTicketAssignDto) { - return await this.ticketAssignService.create(createTicketAssignDto); - } - /* TODO */ - @Get() - findAll() { - return this.ticketAssignService.findAll(); - } - /* TODO */ - @Get(':id') - findOne(@Param('id') id: string) { - return this.ticketAssignService.findOne(+id); - } - /* TODO */ - @Put(':id') - update( - @Param('id') id: string, - @Body() updateTicketAssignDto: UpdateTicketAssignDto, - ) { - return this.ticketAssignService.update(+id, updateTicketAssignDto); - } - /* TODO */ - @Delete(':id') - remove(@Param('id') id: string) { - return this.ticketAssignService.remove(+id); - } -} 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.service.ts b/api/src/assign/ticketassign.service.ts deleted file mode 100644 index 29f3ea4..0000000 --- a/api/src/assign/ticketassign.service.ts +++ /dev/null @@ -1,57 +0,0 @@ -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'; - -/* TODO: - - Implement remaining methods - - Find solution to abstract SQL -*/ -@Injectable() -export class TicketAssignService { - constructor(@Inject(PG_CONNECTION) private connection: Pool) {} - - async create(createTicketAssignDto: CreateTicketAssignDto) { - const { - assignedby, - assignedto, - comment, - assigndate, - } = createTicketAssignDto; - - /* 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`; - } - /* TODO */ - findOne(id: number) { - return `This action returns a #${id} user`; - } - /* TODO */ - update(id: number, updateTicketAssignDto: UpdateTicketAssignDto) { - return `This action updates a #${id} user`; - } - /* TODO */ - remove(id: number) { - return `This action removes a #${id} user`; - } -} diff --git a/api/src/assignment/assignment.controller.ts b/api/src/assignment/assignment.controller.ts new file mode 100644 index 0000000..00d2b80 --- /dev/null +++ b/api/src/assignment/assignment.controller.ts @@ -0,0 +1,45 @@ +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'; + +@ApiTags('assignment') +@Controller('/api/assign') +export class AssignmentController { + constructor(private readonly ticketAssignService: AssignmentService) {} + + /* WORKING Implementation */ + /* TODO: fix date formatting */ + @Post() + async create(@Body() createAssignmentDTO: CreateAssignmentDTO) { + return await this.ticketAssignService.create(createAssignmentDTO); + } + + /* WORKING Implementation */ + @Get() + findAll() { + return this.ticketAssignService.findAll(); + } + + /* WORKING Implementation */ + @Get('user/:lsu_id') + findAllByLsuId(@Param('lsu_id') lsu_id: number) { + return this.ticketAssignService.findAllById(AssignmentType.LSU_ID, lsu_id); + } + + /* WORKING Implementation */ + @Get('ticket/:ticket_id') + findAllByTicketId(@Param('ticket_id') ticket_id: number) { + return this.ticketAssignService.findAllById( + AssignmentType.TICKET_ID, + ticket_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.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/assignment/assignment.service.ts b/api/src/assignment/assignment.service.ts new file mode 100644 index 0000000..97d9b8b --- /dev/null +++ b/api/src/assignment/assignment.service.ts @@ -0,0 +1,141 @@ +import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; +import { Pool, Query, QueryConfig } from 'pg'; +import { PG_CONNECTION } from 'src/connection'; +import { CreateAssignmentDTO } from './dto/create-assignment.dto'; +import { AssignmentDTO, AssignmentType } from './dto/assignment.dto'; +import { createDate } from 'src/util'; + +/* TODO: + - Implement remaining methods + - Find solution to abstract SQL +*/ +@Injectable() +export class AssignmentService { + constructor(@Inject(PG_CONNECTION) private connection: Pool) {} + + async create(createAssignmentDTO: CreateAssignmentDTO) { + 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 */ + 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, + ); + } + } + + 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 */ + 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, + ); + } + } +} diff --git a/api/src/assignment/dto/assignment.dto.ts b/api/src/assignment/dto/assignment.dto.ts new file mode 100644 index 0000000..fcd42c4 --- /dev/null +++ b/api/src/assignment/dto/assignment.dto.ts @@ -0,0 +1,32 @@ +import { ApiProperty } from '@nestjs/swagger'; +export enum AssignmentType { + 'LSU_ID', + 'TICKET_ID', +} +export class AssignmentDTO { + @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 new file mode 100644 index 0000000..533aeaa --- /dev/null +++ b/api/src/assignment/dto/create-assignment.dto.ts @@ -0,0 +1,7 @@ +import { ApiProperty, OmitType as Omit } from '@nestjs/swagger'; +import { AssignmentDTO } from './assignment.dto'; + +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; } 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; +}; 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;