update,
This commit is contained in:
154
_resources/_tecky/party-planner/backend/routes/commentRoutes.ts
Normal file
154
_resources/_tecky/party-planner/backend/routes/commentRoutes.ts
Normal 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'
|
||||
});
|
||||
}
|
||||
}
|
@@ -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'
|
||||
});
|
||||
}
|
||||
}
|
@@ -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'
|
||||
});
|
||||
}
|
||||
}
|
@@ -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'
|
||||
});
|
||||
}
|
||||
}
|
246
_resources/_tecky/party-planner/backend/routes/eventsRoutes.ts
Normal file
246
_resources/_tecky/party-planner/backend/routes/eventsRoutes.ts
Normal 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'
|
||||
});
|
||||
}
|
||||
}
|
175
_resources/_tecky/party-planner/backend/routes/itemsRoutes.ts
Normal file
175
_resources/_tecky/party-planner/backend/routes/itemsRoutes.ts
Normal 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'
|
||||
});
|
||||
}
|
||||
}
|
122
_resources/_tecky/party-planner/backend/routes/loginRoutes.ts
Normal file
122
_resources/_tecky/party-planner/backend/routes/loginRoutes.ts
Normal 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');
|
||||
}
|
@@ -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'
|
||||
});
|
||||
}
|
||||
}
|
@@ -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' });
|
||||
}
|
||||
}
|
627
_resources/_tecky/party-planner/backend/routes/scheduleRoutes.ts
Normal file
627
_resources/_tecky/party-planner/backend/routes/scheduleRoutes.ts
Normal 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'
|
||||
});
|
||||
}
|
||||
}
|
@@ -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'
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user