This commit is contained in:
louiscklaw
2025-01-31 19:15:17 +08:00
parent 09adae8c8e
commit 6c60a73f30
1546 changed files with 286918 additions and 0 deletions

View File

@@ -0,0 +1,154 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { isLoggedInAPI } from '../util/guard';
import { logger } from '../util/logger';
export const commentRoutes = express.Router();
commentRoutes.get('/', isLoggedInAPI, getComment);
commentRoutes.post('/', isLoggedInAPI, postComment);
commentRoutes.put('/', isLoggedInAPI, checkedComment);
async function getComment(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const userId = req.session.user;
const events = (
await client.query(
`
SELECT * from events
JOIN participants ON participants.event_id = events.id
WHERE participants.user_id = $1
`,
[userId]
)
).rows;
const participantComment = (
await client.query(
`
SELECT comments.id, comments.event_id, comments.content, comments.created_at, events.name, users.first_name, users.last_name, comments.read, comments.anonymous FROM participants
JOIN events ON participants.event_id = events.id
JOIN comments ON events.id = comments.event_id
JOIN users on participants.user_id = users.id
WHERE participants.user_id = $1
ORDER BY comments.created_at Desc,
comments.read Asc
`,
[userId]
)
).rows;
const creatorComment = (
await client.query(
`
SELECT comments.read, comments.anonymous, comments.id, comments.event_id, comments.content, comments.created_at, events.name, users.first_name, users.last_name FROM comments
JOIN events ON events.id = comments.event_id
JOIN users ON comments.user_id =users.id
WHERE events.creator_id = $1
ORDER BY comments.created_at Desc,
comments.read Asc
`,
[userId]
)
).rows;
res.json({
status: true,
events: events,
pComment: participantComment,
cComment: creatorComment
});
// 唔好用簡寫
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[CMT001]: Failed to get Comment'
});
}
}
async function postComment(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const userId = req.session.user;
const eventId = parseInt(req.body.receiver);
const category = req.body.category;
const comment = req.body.comment;
const anonymous = req.body.anonymous;
await client.query(
`
INSERT INTO comments
(user_id, event_id, category, content, anonymous, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, NOW(), NOW())
`,
[userId, eventId, category, comment, anonymous]
);
res.json({
status: true,
msg: 'comment sent successfully'
});
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[MSG001]: Failed to send Comment'
});
}
}
async function checkedComment(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const userId = req.session.user;
const commentId = parseInt(req.body.commentId);
const eventId = req.body.eventId;
const read = req.body.check;
let isCreator = true;
const creatorEvent = (
await client.query(
`
SELECT creator_id FROM events
WHERE id = $1
`,
[eventId]
)
).rows[0];
if (creatorEvent.creator_id !== userId) {
isCreator = false;
}
if (isCreator) {
await client.query(
`
UPDATE comments
SET read = $1,
updated_at = $2
WHERE id = $3
`,
[read, 'now()', commentId]
);
res.json({
status: true,
msg: 'Checked/Unchecked'
});
} else {
res.status(400).json({
status: false,
msg: 'Unauthorized Request'
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[MSG002]: Failed to edit Comment'
});
}
}

View File

@@ -0,0 +1,385 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { logger } from '../util/logger';
export const datetimePollRoutes = express.Router();
datetimePollRoutes.get('/:id', getPollOptions);
datetimePollRoutes.post('/:id', createPoll);
datetimePollRoutes.delete('/:id', deletePoll);
datetimePollRoutes.post('/replacement/:id', overwriteTerminatedPoll);
datetimePollRoutes.post('/vote/:event_id/:vote_id', submitVoteChoice);
async function getPollOptions(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const userId = req.session.user;
const [eventDetail] = (
await client.query(
`
SELECT * FROM events WHERE id = $1 AND creator_id = $2;
`,
[eventId, userId]
)
).rows;
if (eventDetail) {
if (eventDetail.date_poll_created) {
const pollOptions = (
await client.query(
`
SELECT * FROM event_date_time WHERE event_id = $1;
`,
[eventId]
)
).rows;
let voteCounts = {};
for (let pollOption of pollOptions) {
const [voteCount] = (
await client.query(
`
SELECT COUNT(*) FROM event_date_time_votes
WHERE event_date_time_id = $1;
`,
[pollOption.id]
)
).rows;
voteCounts[pollOption.id] = voteCount;
}
res.json({
status: true,
creator: true,
pollTerminated: eventDetail.date_poll_terminated,
eventDeleted: eventDetail.deleted,
pollOptions,
voteCounts
});
} else {
res.json({ status: false });
}
} else {
const [participant] = (
await client.query(
`
SELECT * FROM participants
INNER JOIN events ON events.id = participants.event_id
WHERE events.id = $1 AND participants.user_id = $2;
`,
[eventId, userId]
)
).rows;
if (participant) {
const [eventDetailParticipant] = (
await client.query(
`
SELECT * FROM events WHERE id = $1;
`,
[eventId]
)
).rows;
if (eventDetailParticipant.date_poll_created) {
const pollOptions = (
await client.query(
`
SELECT * FROM event_date_time WHERE event_id = $1;
`,
[eventId]
)
).rows;
let voteCounts = {};
for (let pollOption of pollOptions) {
const [voteCount] = (
await client.query(
`
SELECT COUNT(*) FROM event_date_time_votes
WHERE event_date_time_id = $1;
`,
[pollOption.id]
)
).rows;
voteCounts[pollOption.id] = voteCount;
}
const [choiceMade] = (
await client.query(
`
SELECT * FROM event_date_time_votes
WHERE event_date_time_id IN (SELECT id FROM event_date_time
WHERE event_id = $1)
AND user_id = $2;
`,
[eventId, userId]
)
).rows;
let chosenDateTime;
if (choiceMade) {
[chosenDateTime] = (
await client.query(
`
SELECT * FROM event_date_time
WHERE id = $1;
`,
[choiceMade.event_date_time_id]
)
).rows;
}
res.json({
status: true,
creator: false,
pollTerminated: eventDetailParticipant.date_poll_terminated,
eventDeleted: eventDetailParticipant.deleted,
choice: choiceMade
? {
id: `option_${choiceMade.event_date_time_id}`,
start: `${chosenDateTime.start_datetime}`,
end: `${chosenDateTime.end_datetime}`
}
: '',
pollOptions,
voteCounts
});
} else {
res.json({ status: false });
}
} else {
res.json({ status: false });
}
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[DTP001]: Failed to get datetime poll options'
});
}
}
async function createPoll(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND creator_id = $2;
`,
[eventId, req.session.user]
)
).rows;
if (eventDetail) {
if (!eventDetail.date_poll_created) {
const inputList = req.body;
for (let input of inputList) {
await client.query(
`
INSERT INTO event_date_time (start_datetime,end_datetime, event_id, created_at, updated_at)
VALUES ($1,$2,$3,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
`,
[input.start, input.end, eventId]
);
// date_poll_Created is not necessary
await client.query(
`
UPDATE events
SET date_poll_created = TRUE
WHERE id = $1;
`,
[eventId]
);
}
res.json({ status: true });
} else {
res.json({
status: false,
created: true
});
}
} else {
res.json({
status: false
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[DTP002]: Failed to create datetime poll'
});
}
}
async function deletePoll(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND creator_id = $2;
`,
[eventId, req.session.user]
)
).rows;
if (eventDetail) {
if (eventDetail.date_poll_created) {
if (!eventDetail.date_poll_terminated) {
await client.query(
`
UPDATE events SET date_poll_terminated = TRUE
WHERE id = $1;
`,
[eventId]
);
res.json({ status: true });
} else {
res.json({
status: false,
terminated: true
});
}
} else {
res.json({
status: false,
noPoll: true
});
}
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[DTP003]: Failed to delete datetime poll'
});
}
}
async function overwriteTerminatedPoll(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND creator_id = $2;
`,
[eventId, req.session.user]
)
).rows;
if (eventDetail) {
// Initialize the polling data
await client.query(
`
DELETE FROM event_date_time_votes
WHERE event_date_time_id IN (SELECT id FROM event_date_time
WHERE event_id = $1);
`,
[eventId]
);
await client.query(
`
DELETE FROM event_date_time WHERE event_id = $1;
`,
[eventId]
);
await client.query(
`
UPDATE events
SET date_poll_created = FALSE,
date_poll_terminated = FALSE
WHERE id = $1;
`,
[eventId]
);
const inputList = req.body;
for (let input of inputList) {
await client.query(
`
INSERT INTO event_date_time (start_datetime,end_datetime, event_id, created_at, updated_at)
VALUES ($1,$2,$3,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
`,
[input.start, input.end, eventId]
);
await client.query(
`
UPDATE events
SET date_poll_created = TRUE
WHERE id = $1;
`,
[eventId]
);
}
res.json({ status: true });
} else {
res.json({
status: false
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[DTP004]: Failed to overwrite datetime poll'
});
}
}
async function submitVoteChoice(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.event_id);
const userId = req.session.user;
const [participant] = (
await client.query(
`
SELECT * FROM participants
INNER JOIN events ON events.id = participants.event_id
WHERE participants.user_id = $1
AND events.id = $2;
`,
[userId, eventId]
)
).rows;
if (participant) {
const [choiceMade] = (
await client.query(
`
SELECT * FROM event_date_time_votes
WHERE event_date_time_id IN (SELECT id FROM event_date_time
WHERE event_id = $1);
`,
[eventId]
)
).rows;
if (!choiceMade) {
await client.query(
`
INSERT INTO event_date_time_votes
(event_date_time_id,user_id,created_at,updated_at)
VALUES ($1,$2,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
`,
[parseInt(req.params.vote_id), userId]
);
res.json({ status: true });
} else {
res.json({
status: false,
duplicate: true
});
}
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[DTP005]: Failed to submit datetime vote'
});
}
}

View File

@@ -0,0 +1,251 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { logger } from '../util/logger';
import crypto from 'crypto';
export const eventDetailsRoutes = express.Router();
eventDetailsRoutes.get('/created/:id', getCreatedEventDetails);
eventDetailsRoutes.get('/participated/:id', getParticipatedEventDetails);
eventDetailsRoutes.get('/invitation/:id', getInvitationLink);
eventDetailsRoutes.put('/datetime/:id', updateDateTime);
eventDetailsRoutes.put('/venue/:id', updateVenue);
async function getCreatedEventDetails(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.params.id;
const [event] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1
AND creator_id = $2;
`,
[parseInt(eventId), req.session.user]
)
).rows;
if (event) {
const [creatorDetail] = (
await client.query(
`
SELECT * FROM users
WHERE id = $1;
`,
[req.session.user]
)
).rows;
const participantList = (
await client.query(
`
SELECT users.id, users.first_name, users.last_name FROM users
INNER JOIN participants ON participants.user_id = users.id
INNER JOIN events ON participants.event_id = events.id
WHERE events.id = $1;
`,
[parseInt(eventId)]
)
).rows;
res.json({
status: true,
creator: {
id: creatorDetail.id,
first_name: creatorDetail.first_name,
last_name: creatorDetail.last_name
},
detail: event,
participants: participantList
});
} else {
res.json({
status: false
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETD001]: Failed to get Created Event Details'
});
}
}
async function getParticipatedEventDetails(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.params.id;
/*
events
INNER join users as creator on events.creator_id = users.id
INNER JOIN participants on ON participants.event_id = events.id
INNER JOIN users ON participants.user_id = users.id
*/
const [event] = (
await client.query(
`
SELECT events.* FROM events
INNER JOIN participants ON participants.event_id = events.id
INNER JOIN users ON participants.user_id = users.id
WHERE events.id = $1 AND users.id = $2;
`,
[parseInt(eventId), req.session.user]
)
).rows;
if (event) {
const [creatorDetail] = (
await client.query(
`
SELECT * FROM users
INNER JOIN events ON events.creator_id = users.id
WHERE events.id = $1;
`,
[parseInt(eventId)]
)
).rows;
const participantList = (
await client.query(
`
SELECT users.id, users.first_name, users.last_name FROM users
INNER JOIN participants ON participants.user_id = users.id
INNER JOIN events ON participants.event_id = events.id
WHERE events.id = $1;
`,
[parseInt(eventId)]
)
).rows;
res.json({
status: true,
creator: {
id: creatorDetail.id,
first_name: creatorDetail.first_name,
last_name: creatorDetail.last_name
},
detail: event,
participants: participantList
});
} else {
res.json({
status: false
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETD002]: Failed to get Participated Event Details'
});
}
}
async function getInvitationLink(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.params.id;
const [event] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1
AND creator_id = $2;
`,
[parseInt(eventId), req.session.user]
)
).rows;
if (event) {
const invitation_token = crypto.randomBytes(64).toString('hex');
await client.query(
`
UPDATE events SET invitation_token = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2;
`,
[invitation_token, parseInt(eventId)]
);
res.json({
status: true,
invitation_token
});
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETD005]: Failed to copy invitation link'
});
}
}
async function updateDateTime(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.params.id;
// CORRECT
const [event] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1
AND creator_id = $2;
`,
[parseInt(eventId), req.session.user]
)
).rows;
if (event) {
await client.query(
`
UPDATE events
SET start_datetime = $1, end_datetime = $2, updated_at = CURRENT_TIMESTAMP
WHERE id = $3;
`,
[req.body.startTime, req.body.endTime, parseInt(eventId)]
);
res.json({ status: true });
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETD003]: Failed to update date/time'
});
}
}
async function updateVenue(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.params.id;
const [event] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1
AND creator_id = $2;
`,
[parseInt(eventId), req.session.user]
)
).rows;
if (event) {
await client.query(
`
UPDATE events
SET venue = $1, updated_at = CURRENT_TIMESTAMP
WHERE id = $2;
`,
[req.body.venue, parseInt(eventId)]
);
res.json({ status: true });
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETD004]: Failed to update venue'
});
}
}

View File

@@ -0,0 +1,103 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { logger } from '../util/logger';
export const eventInvitationRoutes = express.Router();
eventInvitationRoutes.post('/validation/:eventId/:token', validateInvitationToken);
eventInvitationRoutes.post('/participation/:eventId/:token', joinEvent);
async function validateInvitationToken(req: Request, res: Response) {
try {
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND invitation_token = $2;
`,
[req.params.eventId, req.params.token]
)
).rows;
if (eventDetail) {
res.json({
status: true,
eventDetail
});
} else {
res.json({
status: false,
login: true // 唔洗問client side 的因為server 本身知
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETD005]: Failed to validate invitation link'
});
}
}
async function joinEvent(req: Request, res: Response) {
try {
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND invitation_token = $2;
`,
[req.params.eventId, req.params.token]
)
).rows;
if (eventDetail) {
if (eventDetail.creator_id === req.session.user) {
res.json({
status: false,
login: true,
isCreator: true
});
} else {
const [participant] =
// Insert On Conflict
// Select -> exists -> update
// |-> not exists -> insert
(
await client.query(
`
SELECT * FROM participants
WHERE event_id = $1 AND user_id = $2;
`,
[req.params.eventId, req.session.user]
)
).rows;
if (participant) {
res.json({
status: false,
login: true,
joined: true
});
} else {
await client.query(
`
INSERT INTO participants (event_id, user_id, created_at, updated_at)
VALUES ($1, $2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
`,
[req.params.eventId, req.session.user]
);
res.json({ status: true });
}
}
} else {
res.json({
status: false,
login: true
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETD006]: Failed to join event'
});
}
}

View File

@@ -0,0 +1,246 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { Events } from '../util/models';
import { onlyNumbers } from '../util/functions/onlyNumbers';
import { logger } from '../util/logger';
import { isLoggedInAPI, isLoggedInInvitation } from '../util/guard';
import { eventDetailsRoutes } from './eventDetailsRoutes';
import { venuePollRoutes } from './venuePollRoutes';
import { datetimePollRoutes } from './datetimePollRoutes';
import crypto from 'crypto';
import { eventInvitationRoutes } from './eventInvitationRoutes';
export const eventsRoutes = express.Router();
eventsRoutes.get('/created', isLoggedInAPI, getCreateEventList);
eventsRoutes.get('/participated', isLoggedInAPI, getParticipateEventList);
eventsRoutes.post('/', isLoggedInAPI, postEvent);
eventsRoutes.delete('/:eventId', isLoggedInAPI, deleteEvent);
eventsRoutes.delete('/participants/:eventId', isLoggedInAPI, deleteParticipants);
eventsRoutes.use('/detail', isLoggedInAPI, eventDetailsRoutes);
eventsRoutes.use('/invitation', isLoggedInInvitation, eventInvitationRoutes);
eventsRoutes.use('/poll/venue', isLoggedInAPI, venuePollRoutes);
eventsRoutes.use('/poll/datetime', isLoggedInAPI, datetimePollRoutes);
// getCreatedEvents
async function getCreateEventList(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const [columnCountObject] = (
await client.query(`SELECT COUNT(*) FROM events WHERE creator_id = $1 `, [req.session.user || 0])
).rows;
const columnCount = parseInt(columnCountObject.count);
let currentPage = req.query.page + '';
let offset: number = onlyNumbers(currentPage) ? (parseInt(currentPage) - 1) * 10 : 0;
if (!columnCount) {
currentPage = '1';
offset = 0;
} else if (Math.ceil(columnCount / 10) < parseInt(currentPage)) {
currentPage = Math.ceil(columnCount / 10).toString();
offset = (Math.ceil(columnCount / 10) - 1) * 10;
}
const result = await client.query(
`
SELECT * FROM events
WHERE creator_id = $1
ORDER BY start_datetime DESC, id DESC
LIMIT 10 OFFSET $2;
`,
[req.session.user || 0, offset]
);
const eventList: Events[] = result.rows;
res.json({
object: eventList, // should be called eventList or events
currentPage: currentPage,
page: columnCount ? Math.ceil(columnCount / 10) : 1
});
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[EVT001]: Failed to get Created Event List'
});
}
}
// getParticipatedEvents
async function getParticipateEventList(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const [columnCountObject] = (
await client.query(
`SELECT COUNT(events.*) FROM events
INNER JOIN participants ON participants.event_id = events.id
INNER JOIN users ON participants.user_id = users.id
WHERE users.id = $1;`,
[req.session.user || 0]
)
).rows;
const columnCount = parseInt(columnCountObject.count);
let currentPage = req.query.page as string;
let offset: number = onlyNumbers(currentPage) ? (parseInt(currentPage) - 1) * 10 : 0;
if (!columnCount) {
currentPage = '1';
offset = 0;
} else if (Math.ceil(columnCount / 10) < parseInt(currentPage)) {
currentPage = Math.ceil(columnCount / 10).toString();
offset = (Math.ceil(columnCount / 10) - 1) * 10;
}
const result = await client.query(
`
SELECT events.* FROM events
INNER JOIN participants ON participants.event_id = events.id
INNER JOIN users ON participants.user_id = users.id
WHERE users.id = $1
ORDER BY events.start_datetime DESC, events.id DESC
LIMIT 10 OFFSET $2;
`,
[req.session.user || 0, offset]
);
const eventList: Events[] = result.rows;
res.json({
object: eventList,
currentPage: currentPage,
page: columnCount ? Math.ceil(columnCount / 10) : 1
});
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[EVT002]: Failed to get Participated Event List'
});
}
}
async function postEvent(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const invitation_token = crypto.randomBytes(64).toString('hex');
await client.query(
`INSERT INTO events
(name, venue, start_datetime, end_datetime,
creator_id, invitation_token, deleted,
date_poll_created,
date_poll_terminated,
venue_poll_created,
venue_poll_terminated,
created_at, updated_at)
VALUES ($1,$2,$3,$4,$5,$6,FALSE,FALSE,FALSE,FALSE,FALSE,
CURRENT_TIMESTAMP,CURRENT_TIMESTAMP)`,
[
req.body.eventName,
req.body.eventVenue,
req.body.startTime,
req.body.endTime,
req.session.user,
invitation_token
]
);
res.json({ msg: 'Posted to DB' });
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[EVT003]: Failed to post Event' });
}
}
async function deleteParticipants(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.params.eventId ? parseInt(req.params.eventId) : 0;
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE creator_id = $1
AND id = $2;
`,
[req.session.user, eventId]
)
).rows;
const deletedParticipants: { id: number }[] = req.body.deletedParticipants;
if (eventDetail) {
const participantsWithItemAssigned = await client.query(
`
SELECT user_id FROM items
WHERE user_id = ANY($1::int[])
`,
[deletedParticipants.map((p) => p.id)]
);
console.log(participantsWithItemAssigned);
// Removed all of the ids from participantsWithItemAssigned
// Then run delete
let notDeletable = [];
for (let deletedParticipant of req.body) {
// n + 1 problem
const itemInCharge = (
await client.query(
`
SELECT * FROM items
WHERE user_id = $1 AND event_id = $2 AND purchased = FALSE;
`,
[deletedParticipant.id, eventId]
)
).rows;
if (itemInCharge.length) {
notDeletable.push({
deletedParticipant,
itemInCharge
});
} else {
await client.query(
`
DELETE FROM participants WHERE user_id = $1 and event_id = $2;
`,
[deletedParticipant.id, eventId]
);
}
}
res.json({
status: true,
notDeletable
});
} else {
res.status(500).json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[EVT004]: Failed to delete Participants'
});
}
}
// Archived
async function deleteEvent(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.params.eventId ? parseInt(req.params.eventId) : 0;
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE creator_id = $1
AND id = $2;
`,
[req.session.user, eventId]
)
).rows;
if (eventDetail) {
// Marked Delete
await client.query(
`
UPDATE events SET deleted = TRUE
WHERE id = $1;
`,
[eventId]
);
res.json({ status: true });
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[EVT005]: Failed to delete Event'
});
}
}

View File

@@ -0,0 +1,175 @@
import express, { Request, Response } from 'express';
import { logger } from '../util/logger';
import { client } from '../app';
export const itemsRoutes = express.Router();
itemsRoutes.get('/participated', getParticipateEventList);
itemsRoutes.get('/', getItem);
itemsRoutes.post('/eventId/:id', postItem);
itemsRoutes.delete('/:id', deleteItem);
itemsRoutes.get('/pendingItems', getPendingItem);
itemsRoutes.put('/pendingItems/:id', updateItemStatus);
enum TypeName {
Food = 'food',
Drink = 'drink',
Decoration = 'decoration',
Other = 'other'
}
export type ItemType = 'food' | 'drink' | 'decoration' | 'other';
async function getItem(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
// Can use group by
const itemResult = await client.query(
`
SELECT items.type_name, items.name, items.quantity, items.price, items.id, users.first_name, users.last_name
FROM items
INNER JOIN users ON users.id = items.user_id
WHERE event_id = $1
`,
[req.query.eventID]
);
const itemObj = {
[TypeName.Food]: [],
[TypeName.Drink]: [],
[TypeName.Decoration]: [],
[TypeName.Other]: []
};
for (const items of itemResult.rows) {
itemObj[items.type_name].push(items);
}
res.json({ itemObj, status: true, msg: 'get item from DB' });
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[ITM001]: Failed to post Item' });
}
}
async function getParticipateEventList(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const participateResult = await client.query(
`
SELECT users.first_name, users.last_name, users.id
FROM participants
INNER JOIN users ON users.id = participants.user_id
WHERE event_id =$1
`,
[req.query.eventID]
);
res.json({
user: participateResult.rows,
status: true,
msg: 'get participant from DB'
});
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[ITM002]: Failed to post Item' });
}
}
async function postItem(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const result = await client.query(
`INSERT INTO items
(type_name, name, quantity, price, user_id, event_id, purchased,
created_at, updated_at )
VALUES ($1,$2,$3,$4,$5,$6,FALSE, NOW(), NOW())
RETURNING *
`,
[
req.body.typeName,
req.body.itemName,
req.body.itemQuantity,
req.body.itemPrice,
req.body.user_id,
req.params.id
]
);
res.json({ result: result.rows, status: true, msg: 'Posted to DB' });
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[ITM005]: Failed to post Item' });
}
}
async function deleteItem(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
await client.query(
`
DELETE FROM items where items.id = $1
`,
[req.params.id]
);
res.json({ status: true, msg: 'successfully delete' });
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[ITM006]: Failed to post Item' });
}
}
async function getPendingItem(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const result = await client.query(
`
SELECT items.name, items.id, items.type_name FROM items
WHERE purchased = false AND event_id = $1
`,
[req.query.eventID]
);
const itemObj = {
[TypeName.Food]: [],
[TypeName.Drink]: [],
[TypeName.Decoration]: [],
[TypeName.Other]: []
};
for (const items of result.rows) {
itemObj[items.type_name].push(items);
}
res.json({ itemObj, status: true, msg: 'get pending items from DB' });
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[ITM007]: Failed to post Pending Items' });
}
}
async function updateItemStatus(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const result = await client.query(
`
UPDATE items SET purchased = true
WHERE items.id = $1
`,
[req.params.id]
);
res.json({
updateItem: result.rows,
status: true,
msg: 'update pending items from DB'
});
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ITM008]: Failed to update Pending Items'
});
}
}

View File

@@ -0,0 +1,122 @@
import express, { Request, Response } from 'express';
import { logger } from '../util/logger';
import { client } from '../app';
import { checkPassword } from '../util/functions/hash';
import fetch from 'cross-fetch';
import crypto from 'crypto';
export const loginRoutes = express.Router();
loginRoutes.get('/', checkSessionLogin); // not necessary
loginRoutes.post('/', login);
loginRoutes.get('/name', getName);
loginRoutes.post('/logout', logout);
loginRoutes.get('/google', loginGoogle);
//not necessary
async function checkSessionLogin(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
if (req.session.user) {
const loginUser = (await client.query(`SELECT * FROM users WHERE id = $1`, [req.session.user])).rows[0];
if (loginUser) {
res.json({ status: true });
} else {
res.status(401).json({ status: false });
}
} else {
res.status(401).json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[LOG001]: Failed to check Login' });
}
}
async function login(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const loginUser = (await client.query(`SELECT * FROM users WHERE email = $1`, [req.body.email])).rows[0];
if (loginUser) {
const match = await checkPassword(req.body.password, loginUser.password);
if (match) {
req.session.user = loginUser.id;
res.json({
status: true,
user: loginUser.email
});
} else {
res.status(401).json({ status: false });
}
} else {
res.status(401).json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[LOG002]: Failed to check Login' });
}
}
async function getName(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const userName = (await client.query(`SELECT * FROM users WHERE id = $1`, [req.session.user])).rows[0];
if (userName) {
res.json({
status: true,
user: userName.first_name
});
} else {
res.status(401).json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[LOG003]: Failed to get Name' });
}
}
async function logout(req: Request, res: Response) {
try {
logger.debug('Before logging out');
delete req.session.user;
res.json({ status: true });
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[LOG004]: Failed to Logout' });
}
}
async function loginGoogle(req: express.Request, res: express.Response) {
const accessToken = req.session?.['grant'].response.access_token;
const fetchRes = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
method: 'get',
headers: {
Authorization: `Bearer ${accessToken}`
}
});
const result = await fetchRes.json();
const password = `google_user_` + crypto.randomBytes(20).toString('hex');
const users = (await client.query(`SELECT * FROM users WHERE email = $1`, [result.email])).rows;
let user = users[0];
if (!user) {
user = (
await client.query(
`INSERT INTO users (first_name, last_name, password, phone, email, created_at, updated_at)
VALUES ($1,$2,$3,$4,$5,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP) RETURNING *`,
[result.given_name, result.family_name, password, '', result.email]
)
).rows[0];
console.log(`User with id ${user.id} is created`);
}
if (req.session) {
req.session.user = user.id;
}
res.redirect('/index.html');
}

View File

@@ -0,0 +1,76 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { checkPassword, hashPassword } from '../util/functions/hash';
import { logger } from '../util/logger';
import { Users } from '../util/models';
import { isLoggedInAPI } from '../util/guard';
export const personalInfoRoutes = express.Router();
personalInfoRoutes.get('/', isLoggedInAPI, getPersonalInfo);
personalInfoRoutes.put('/', isLoggedInAPI, updatePersonalInfo);
async function getPersonalInfo(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const result = await client.query(
`SELECT * FROM users
WHERE id = $1
`,
[req.session.user]
);
const user: Users = result.rows[0];
res.json(user);
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ERR001]: Failed to get information'
});
}
}
async function updatePersonalInfo(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
await client.query(
`UPDATE users
SET first_name = $1, last_name = $2, phone = $3, updated_at = CURRENT_TIMESTAMP
WHERE id = $4`,
[req.body.first_name, req.body.last_name, req.body.phone, req.session.user]
);
if (req.body.current_password) {
//check if input password is correct
const hashedPassword = await client.query(
`SELECT password FROM users
WHERE id = $1`,
[req.session.user]
);
if (!(await checkPassword(req.body.current_password, hashedPassword.rows[0].password))) {
res.status(400);
throw new Error(`Failed login attempt from user ${req.session.user}`);
}
// update DB with new password
const password = await hashPassword(req.body.password);
await client.query(
`UPDATE users
SET password = $1, updated_at = CURRENT_TIMESTAMP
WHERE id = $2`,
[password, req.session.user]
);
}
res.json({ status: true });
} catch (e) {
logger.error(e);
res.status(400).json({
msg: '[UPD001]: Failed to update information at Database'
});
}
}

View File

@@ -0,0 +1,37 @@
import express, { Request, Response } from 'express';
import { logger } from '../util/logger';
import { client } from '../app';
import { hashPassword } from '../util/functions/hash';
export const registerRoutes = express.Router();
registerRoutes.post('/', registerUser);
async function registerUser(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
// Needs to send email SMS verification if you really want to enforce them to be unique.
const loginUser = (
await client.query(`SELECT * FROM users WHERE email = $1 OR phone = $2`, [
req.body.email,
!!req.body.phone ? req.body.phone : '0'
])
).rows[0];
if (!loginUser) {
const password = await hashPassword(req.body.password);
await client.query(
`INSERT INTO users (first_name, last_name, email, phone, password, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);`,
[req.body.first_name, req.body.last_name, req.body.email, req.body.phone, password]
);
res.json({ status: true });
} else {
res.status(401).json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({ msg: '[REG001]: Failed to Register' });
}
}

View File

@@ -0,0 +1,627 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { isLoggedInAPI } from '../util/guard';
import { logger } from '../util/logger';
export const scheduleRoutes = express.Router();
scheduleRoutes.get('/', isLoggedInAPI, getEventSchedule);
scheduleRoutes.post('/activity', isLoggedInAPI, postEventSchedule);
scheduleRoutes.put('/description/edit', isLoggedInAPI, editDescription);
scheduleRoutes.put('/remark/edit', isLoggedInAPI, editRemark);
scheduleRoutes.put('/timeName/edit', isLoggedInAPI, editTimeName);
scheduleRoutes.post('/item', isLoggedInAPI, postItem);
scheduleRoutes.delete('/timeBlock/', isLoggedInAPI, deleteTimeBlock);
// select * from time_blocks where start_time
// between '2022-10-12T10:00:00' and '2022-10-12T12:00:00'
// or end_time between '2022-10-12T10:00:00' and '2022-10-12T12:00:00';
// Date <- Birthday , no need to do comparison , Time is not useful
// Time <- only if it is not a moment, but a periodic time. "Every day 3pm"
// Datetime <- everything else
async function postItem(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const creator = req.query['is-creator'];
const timeBlockId = req.query['id'];
const itemList = req.body;
const eventId = req.query['event-id'];
const event = (
await client.query(
`
SELECT start_datetime, end_datetime, deleted FROM events
WHERE id = $1
`,
[eventId]
)
).rows[0];
const isDeleted = event.deleted;
const eventStartTimeInMin = event.start_datetime.getTime();
const eventEndTimeInMin = event.end_datetime.getTime();
const now = new Date().getTime();
let isProcessing = true;
if (eventStartTimeInMin < now && eventEndTimeInMin < now) {
isProcessing = false;
//event is finished
}
if (isDeleted) {
isProcessing = false;
//event was deleted by creator
}
if (creator === '1' && isProcessing) {
// delete existing list
await client.query(
`
DELETE FROM time_block_item
WHERE time_block_item.time_block_id = $1
`,
[timeBlockId]
);
itemList.forEach(async (item: any) => {
await client.query(
`
INSERT INTO time_block_item (time_block_id, item_id, created_at, updated_at)
VALUES ($1, $2, $3, $4)
`,
[timeBlockId, `${item}`, 'now()', 'now()']
);
});
res.json({
status: true,
msg: 'Items Added'
});
} else {
res.status(400).json({
msg: '[EER001]: Unauthorized Request'
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ITM003]: Failed to Add Show Item'
});
}
}
async function editTimeName(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.query['event-id'];
const creator = req.query['is-creator'];
const timeBlockId = parseInt(req.query['id'] as string);
const date = req.query.date;
const title = req.body.title;
const startTime = req.body.editStartTime;
const endTime = req.body.editEndTime;
const color = req.body.editColor;
const event = (
await client.query(
`
SELECT start_datetime, end_datetime, deleted FROM events
WHERE id = $1
`,
[eventId]
)
).rows[0];
const isDeleted = event.deleted;
const eventStartTimeInMin = event.start_datetime.getTime();
const eventEndTimeInMin = event.end_datetime.getTime();
const now = new Date().getTime();
let isProcessing = true;
if (eventStartTimeInMin < now && eventEndTimeInMin < now) {
isProcessing = false;
//event is finished
}
if (isDeleted) {
isProcessing = false;
//event was deleted by creator
}
if (creator === '1' && isProcessing) {
//check time collision with existing time-blocks
//bug: correct end time = 00:00 problem
const existingActivities = (
await client.query(
`
SELECT start_time, end_time, id FROM time_blocks
WHERE event_id = $1
AND date = $2
AND id != $3
ORDER BY start_time ASC;
`,
[eventId, date, timeBlockId]
)
).rows;
let reject = false;
const newStartTimeInMin = toMin(req.body.editStartTime);
const newEndTimeInMin = toMin(req.body.editEndTime);
existingActivities.forEach((activity) => {
const startTimeInMin = toMin(activity.start_time);
const endTimeInMin = toMin(activity.end_time);
if (newStartTimeInMin > startTimeInMin && newStartTimeInMin < endTimeInMin) {
reject = true;
console.log('1');
}
if (newEndTimeInMin > startTimeInMin && newEndTimeInMin < endTimeInMin) {
reject = true;
console.log('2');
}
if (newStartTimeInMin <= startTimeInMin && newEndTimeInMin >= endTimeInMin) {
reject = true;
console.log('3');
}
});
//writing update to DB
if (reject) {
res.status(400).json({
msg: '[EER002]: Activity Start Time or End Time Overlapped with Existing Activity'
});
} else {
await client.query(
`
UPDATE time_blocks
SET title = $1,
start_time = $2,
end_time = $3,
color = $4,
updated_at = $5
WHERE event_id = $6
AND id = $7
AND date = $8
`,
[title, startTime, endTime, color, 'now()', eventId, timeBlockId, date]
);
res.json({
status: true,
msg: 'Edit success'
});
}
} else {
res.json({
status: false,
msg: '[EER001]: Unauthorized Request'
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[TBE002]: Failed to Edit Time & Name'
});
}
}
async function editRemark(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.query['event-id'];
const creator = req.query['is-creator'];
const timeBlockId = req.query['id'];
const date = req.query.date;
const remark = req.body.remark;
const event = (
await client.query(
`
SELECT start_datetime, end_datetime, deleted FROM events
WHERE id = $1
`,
[eventId]
)
).rows[0];
const isDeleted = event.deleted;
const eventStartTimeInMin = event.start_datetime.getTime();
const eventEndTimeInMin = event.end_datetime.getTime();
const now = new Date().getTime();
let isProcessing = true;
if (eventStartTimeInMin < now && eventEndTimeInMin < now) {
isProcessing = false;
//event is finished
}
if (isDeleted) {
isProcessing = false;
//event was deleted by creator
}
if (creator === '1' && isProcessing) {
await client.query(
`
UPDATE time_blocks
SET remark = $1,
updated_at = $2
WHERE event_id = $3
AND id = $4
AND date = $5
`,
[remark, 'now()', eventId, timeBlockId, date]
);
res.json({
status: true,
msg: 'Edit success'
});
} else {
res.json({
status: false,
msg: '[EER001]: Unauthorized Request'
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[TBE001]: Failed to Edit Remark'
});
}
}
async function editDescription(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.query['event-id'];
const creator = req.query['is-creator'];
const timeBlockId = req.query['id'];
const date = req.query.date;
const description = req.body.description;
const event = (
await client.query(
`
SELECT start_datetime, end_datetime, deleted FROM events
WHERE id = $1
`,
[eventId]
)
).rows[0];
const isDeleted = event.deleted;
const eventStartTimeInMin = event.start_datetime.getTime();
const eventEndTimeInMin = event.end_datetime.getTime();
const now = new Date().getTime();
let isProcessing = true;
if (eventStartTimeInMin < now && eventEndTimeInMin < now) {
isProcessing = false;
//event is finished
}
if (isDeleted) {
isProcessing = false;
//event was deleted by creator
}
if (creator === '1' && isProcessing) {
await client.query(
`
UPDATE time_blocks
SET description = $1,
updated_at = $2
WHERE event_id = $3
AND id = $4
AND date = $5
`,
[description, 'now()', eventId, timeBlockId, date]
);
res.json({
status: true,
msg: 'Edit success'
});
} else {
res.json({
status: false,
msg: '[EER001]: Unauthorized Request'
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[TBE003]: Failed to Edit Description'
});
}
}
async function deleteTimeBlock(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.query['event-id'];
const creator = req.query['is-creator'];
const timeBlockId = req.query['id'];
const date = req.query.date;
const event = (
await client.query(
`
SELECT start_datetime, end_datetime, deleted FROM events
WHERE id = $1
`,
[eventId]
)
).rows[0];
const isDeleted = event.deleted;
const eventStartTimeInMin = event.start_datetime.getTime();
const eventEndTimeInMin = event.end_datetime.getTime();
const now = new Date().getTime();
let isProcessing = true;
if (eventStartTimeInMin < now && eventEndTimeInMin < now) {
isProcessing = false;
//event is finished
}
if (isDeleted) {
isProcessing = false;
//event was deleted by creator
}
if (creator === '1' && isProcessing) {
await client.query(
`
DELETE FROM time_block_item
WHERE time_block_id = $1
`,
[timeBlockId]
);
await client.query(
`
DELETE FROM time_blocks
WHERE id = $1
AND event_id = $2
AND date = $3
`,
[timeBlockId, eventId, date]
);
res.json({
status: true,
msg: 'Delete success'
});
} else {
res.status(400).json({
status: false,
msg: '[EER001]: Unauthorized Request'
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[TBD001]: Failed to Delete Time Block'
});
}
}
async function getEventSchedule(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.query['event-id'];
const creator = req.query['is-creator'];
let date = req.query.date;
let event;
if (creator === '1') {
event = (
await client.query(
`
SELECT * FROM events
WHERE events.id = $1
AND events.creator_id = $2
`,
[eventId, req.session.user]
)
).rows[0];
} else {
event = (
await client.query(
`
SELECT * FROM events
INNER JOIN participants ON participants.event_id = events.id
WHERE events.id = $1
AND participants.user_id = $2;
`,
[eventId, req.session.user]
)
).rows[0];
}
if (event.start_datetime) {
if (date === 'null' || 'undefined') {
const option = {
hour12: false,
year: 'numeric',
month: '2-digit',
day: '2-digit'
};
let placeholder = event.start_datetime.toLocaleString('en-GB', option).split('/');
date = `${placeholder[2]}${placeholder[1]}${placeholder[0]}`;
}
const activitiesArr = (
await client.query(
`
SELECT * FROM time_blocks
WHERE event_id = $1
AND date = $2
`,
[eventId, date]
)
).rows;
const itemList = (
await client.query(
`
SELECT * FROM items
WHERE items.event_id = $1
`,
[eventId]
)
).rows;
const savedItemList = (
await client.query(
`
SELECT * FROM items
JOIN time_block_item ON items.id = time_block_item.item_id
JOIN time_blocks ON time_block_item.time_block_id = time_blocks.id
WHERE time_blocks.event_id = $1
AND time_blocks.date = $2
`,
[eventId, date]
)
).rows;
res.json({
status: true,
detail: event,
activities: activitiesArr,
items: itemList,
savedItems: savedItemList
});
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETS001]: Failed to get Event Schedule'
});
}
}
function toMin(timeInput: String) {
const hourInMin = parseInt(timeInput.slice(0, 2)) * 60;
const min = parseInt(timeInput.slice(3, 5));
return hourInMin + min;
}
async function postEventSchedule(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = req.query['event-id'];
const creator = req.query['is-creator'];
const date = req.query.date;
const event = (
await client.query(
`
SELECT start_datetime, end_datetime, deleted FROM events
WHERE id = $1
`,
[eventId]
)
).rows[0];
const isDeleted = event.deleted;
const eventStartTimeInMin = event.start_datetime.getTime();
const eventEndTimeInMin = event.end_datetime.getTime();
const now = new Date().getTime();
let isProcessing = true;
if (eventStartTimeInMin < now && eventEndTimeInMin < now) {
isProcessing = false;
//event is finished
}
if (isDeleted) {
isProcessing = false;
//event was deleted by creator
}
if (creator === '1' && isProcessing) {
//check if start time and end time collided with existing activities
const existingActivities = (
await client.query(
`
SELECT start_time, end_time FROM time_blocks
WHERE event_id = $1
AND date = $2
ORDER BY start_time ASC;
`,
[eventId, date]
)
).rows;
let reject = false;
existingActivities.forEach((activity) => {
const startTimeInMin = toMin(activity.start_time);
const endTimeInMin = toMin(activity.end_time);
const newStartTimeInMin = toMin(req.body.startTime);
const newEndTimeInMin = toMin(req.body.endTime);
if (newStartTimeInMin > startTimeInMin && newStartTimeInMin < endTimeInMin) {
reject = true;
} else if (newEndTimeInMin > startTimeInMin && newEndTimeInMin < endTimeInMin) {
reject = true;
}
});
//writing request to DB
if (reject) {
res.status(400).json({
msg: '[EER002]: Activity Start Time or End Time Overlapped with Existing Activity'
});
} else {
await client.query(
`
INSERT INTO time_blocks
(title, description, event_id, user_id, start_time,
end_time, remark, date, color, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
[
req.body.title,
req.body.description,
eventId,
req.session.user,
req.body.startTime,
req.body.endTime,
req.body.remark,
date,
req.body.color,
'now()',
'now()'
]
);
res.json({
status: true,
msg: 'save success'
});
}
} else {
res.status(400).json({
msg: '[EER001]: Unauthorized Request'
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[ETS002]: Failed to Post Event Schedule'
});
}
}

View File

@@ -0,0 +1,394 @@
import express, { Request, Response } from 'express';
import { client } from '../app';
import { logger } from '../util/logger';
export const venuePollRoutes = express.Router();
venuePollRoutes.get('/:id', getPollOptions);
venuePollRoutes.post('/:id', createPoll);
venuePollRoutes.delete('/:id', deletePoll);
venuePollRoutes.post('/replacement/:id', replaceTerminatedPoll);
venuePollRoutes.post('/vote/:event_id/:vote_id', submitVoteChoice);
async function getPollOptions(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const userId = req.session.user;
const [eventDetail] = (
await client.query(
`
SELECT * FROM events WHERE id = $1 AND creator_id = $2;
`,
[eventId, userId]
)
).rows;
if (eventDetail) {
if (eventDetail.venue_poll_created) {
const pollNew = (await client.query(`
SELECT event_venues.id as option_id,
event_venues.address as address,
event_venues_votes.id as votes_id
FROM event_venues
LEFT JOIN event_venues_votes ON event_venues_votes.event_venues_id = event_venues.id
WHERE event_venues.event_id = $1;
`,
[eventId]
)).rows;
let pollOptions: {
id: number,
address: string
}[] = [];
let voteCounts:{
[keys in number]: {
count: number
}
} = {};
for (let eachVote of pollNew) {
if (!pollOptions.find((obj)=>obj.id === eachVote.option_id)) {
pollOptions.push({
id: eachVote.option_id,
address: eachVote.address
});
voteCounts[eachVote.option_id] = {count: 0};
}
if (eachVote.votes_id) {
voteCounts[eachVote.option_id].count ++;
}
}
res.json({
status: true,
creator: true,
pollTerminated: eventDetail.venue_poll_terminated,
eventDeleted: eventDetail.deleted,
pollOptions,
voteCounts
});
} else {
res.json({ status: false });
}
} else {
// Should be participants join events join event_venues join event_venue_votes
const [participant] = (
await client.query(
`
SELECT * FROM participants
INNER JOIN events ON events.id = participants.event_id
WHERE events.id = $1 AND participants.user_id = $2;
`,
[eventId, userId]
)
).rows;
if (participant) {
const [eventDetailParticipant] = (
await client.query(
`
SELECT * FROM events WHERE id = $1;
`,
[eventId]
)
).rows;
if (eventDetailParticipant.venue_poll_created) {
const pollOptions = (
await client.query(
`
SELECT * FROM event_venues WHERE event_id = $1;
`,
[eventId]
)
).rows;
let voteCounts = {};
for (let pollOption of pollOptions) {
const [voteCount] = (
await client.query(
`
SELECT COUNT(*) FROM event_venues_votes
WHERE event_venues_id = $1;
`,
[pollOption.id]
)
).rows;
voteCounts[pollOption.id] = voteCount;
}
const [choiceMade] = (
await client.query(
`
SELECT * FROM event_venues_votes
WHERE event_venues_id IN (SELECT id FROM event_venues
WHERE event_id = $1)
AND user_id = $2;
`,
[eventId, userId]
)
).rows;
let chosenAddress;
if (choiceMade) {
[chosenAddress] = (
await client.query(
`
SELECT * FROM event_venues
WHERE id = $1;
`,
[choiceMade.event_venues_id]
)
).rows;
}
res.json({
status: true,
creator: false,
pollTerminated: eventDetailParticipant.venue_poll_terminated,
eventDeleted: eventDetailParticipant.deleted,
choice: choiceMade
? {
id: `option_${choiceMade.event_venues_id}`,
address: `${chosenAddress.address}`
}
: '',
pollOptions,
voteCounts
});
} else {
res.json({ status: false });
}
} else {
res.json({ status: false });
}
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[VNP001]: Failed to get venue poll options'
});
}
}
async function createPoll(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND creator_id = $2;
`,
[eventId, req.session.user]
)
).rows;
if (eventDetail) {
if (!eventDetail.venue_poll_created) {
const inputList = req.body;
for (let input of inputList) {
await client.query(
`
INSERT INTO event_venues (address, event_id, created_at, updated_at)
VALUES ($1,$2,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
`,
[input, eventId]
);
await client.query(
`
UPDATE events
SET venue_poll_created = TRUE
WHERE id = $1;
`,
[eventId]
);
}
res.json({ status: true });
} else {
res.json({
status: false,
created: true
});
}
} else {
res.json({
status: false
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[VNP002]: Failed to create venue poll'
});
}
}
async function deletePoll(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND creator_id = $2;
`,
[eventId, req.session.user]
)
).rows;
if (eventDetail) {
if (eventDetail.venue_poll_created) {
if (!eventDetail.venue_poll_terminated) {
await client.query(
`
UPDATE events SET venue_poll_terminated = TRUE
WHERE id = $1;
`,
[eventId]
);
res.json({ status: true });
} else {
res.json({
status: false,
terminated: true
});
}
} else {
res.json({
status: false,
noPoll: true
});
}
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[VNP003]: Failed to delete venue poll'
});
}
}
// Should not have poll_created as the column , but poll_terminated can retain
async function replaceTerminatedPoll(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.id);
const [eventDetail] = (
await client.query(
`
SELECT * FROM events
WHERE id = $1 AND creator_id = $2;
`,
[eventId, req.session.user]
)
).rows;
if (eventDetail) {
// Initialize the polling data
await client.query(
`
DELETE FROM event_venues_votes
WHERE event_venues_id IN (SELECT id FROM event_venues
WHERE event_id = $1);
`,
[eventId]
);
await client.query(
`
DELETE FROM event_venues WHERE event_id = $1;
`,
[eventId]
);
await client.query(
`
UPDATE events
SET venue_poll_created = FALSE,
venue_poll_terminated = FALSE
WHERE id = $1;
`,
[eventId]
);
const inputList = req.body;
for (let input of inputList) {
await client.query(
`
INSERT INTO event_venues (address, event_id, created_at, updated_at)
VALUES ($1,$2,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
`,
[input, eventId]
);
await client.query(
`
UPDATE events
SET venue_poll_created = TRUE
WHERE id = $1;
`,
[eventId]
);
}
res.json({ status: true });
} else {
res.json({
status: false
});
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[VNP004]: Failed to overwrite venue poll'
});
}
}
async function submitVoteChoice(req: Request, res: Response) {
try {
logger.debug('Before reading DB');
const eventId = parseInt(req.params.event_id);
const userId = req.session.user;
const [participant] = (
await client.query(
`
SELECT * FROM participants
INNER JOIN events ON events.id = participants.event_id
WHERE participants.user_id = $1
AND events.id = $2;
`,
[userId, eventId]
)
).rows;
if (participant) {
const [choiceMade] = (
await client.query(
`
SELECT * FROM event_venues_votes
WHERE event_venues_id IN (SELECT id FROM event_venues
WHERE event_id = $1);
`,
[eventId]
)
).rows;
if (!choiceMade) {
await client.query(
`
INSERT INTO event_venues_votes
(event_venues_id,user_id,created_at,updated_at)
VALUES ($1,$2,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP);
`,
[parseInt(req.params.vote_id), userId]
);
res.json({ status: true });
} else {
res.json({
status: false,
duplicate: true
});
}
} else {
res.json({ status: false });
}
} catch (e) {
logger.error(e);
res.status(500).json({
msg: '[VNP005]: Failed to submit vote choice'
});
}
}