Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge dev into main #33

Merged
merged 26 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d560285
created catalog table
Nov 18, 2023
8b92d59
AT - created the published schedule table
arralia Nov 19, 2023
a499026
fixed enum name
arralia Nov 19, 2023
1155340
removed brackets around exist conditionals
arralia Nov 19, 2023
0e83312
added create table users statement
Nov 19, 2023
e2e0b73
added drop table if exists
Nov 19, 2023
19035e2
updated drop table statement
Nov 19, 2023
d68a4d2
Made CRUD SQL queries for Published Schedule Table
SubinQKim Nov 20, 2023
847c958
added catalog CRUD queries
chloecheng8 Nov 21, 2023
589e537
Attempt to figure out ENV variable issue with workflows
leeaj8-uci Nov 22, 2023
9f350b0
fix typo
leeaj8-uci Nov 22, 2023
559dab7
try moving env variables
leeaj8-uci Nov 22, 2023
f810b9d
Revert changes
leeaj8-uci Nov 22, 2023
34eff36
Merge pull request #14 from ctc-uci/8-create-catalog-table
ThatMegamind Nov 22, 2023
80ac134
Merge pull request #15 from ctc-uci/7-create-published-schedule-table
ThatMegamind Nov 22, 2023
fe99a58
Merge pull request #16 from ctc-uci/9-create-user-table
ThatMegamind Nov 22, 2023
5ad36f1
Merge pull request #17 from ctc-uci/10-make-crud-sql-queries-for-publ…
ThatMegamind Nov 22, 2023
32a94b0
Merge pull request #18 from ctc-uci/11-make-crud-sql-queries-for-cata…
ThatMegamind Nov 23, 2023
c042554
Make CRUD SQL queries for Users Table (#25)
ctc-devops Nov 25, 2023
57cc996
fixed published schedule types
michellelin1 Nov 27, 2023
8c703e9
added connection to db
michellelin1 Nov 27, 2023
15d3d25
23-make-backend-routes-for-users (#26)
ctc-devops Dec 18, 2023
a2965f7
Make backend routes for Catelog (#27)
ctc-devops Dec 18, 2023
e6e02f1
Set up the nodeMailer route and the transporter (#28)
ctc-devops Dec 30, 2023
699f437
Make Backend Routes for Published Schedule (#29)
ctc-devops Jan 3, 2024
39cccb0
Minor DB Updates (#32)
ctc-devops Jan 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ name: CI

on:
[pull_request]

permissions: read-all

jobs:
eslint:
eslint:
runs-on: ubuntu-latest
steps:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
Expand All @@ -21,7 +21,7 @@ jobs:
reporter: github-pr-review
fail_on_error: false
eslint_flags: '**/*.{js,jsx}'

detect-secrets:
runs-on: ubuntu-latest
steps:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/scripts/reviewReviewed.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ const messageAssignee = async ({ context }) => {
try {
const UserModel = getUserModel();
const slackAssignees = await Promise.allSettled(
githubAssignees.map(assignee => UserModel.findOne({ github: assignee.login })),
githubAssignees.map((assignee) => UserModel.findOne({ github: assignee.login })),
);
if (context.payload.review.state === 'approved') {
await Promise.all(
slackAssignees.map(assignee =>
slackAssignees.map((assignee) =>
Bot.client.chat.postMessage({
channel: assignee.value?.slackId,
text: `One of your pull requests has been APPROVED by ${reviewer}! <${url}|View Review> :shrek::thumbsup:`,
Expand All @@ -53,7 +53,7 @@ const messageAssignee = async ({ context }) => {
);
} else {
await Promise.all(
slackAssignees.map(assignee =>
slackAssignees.map((assignee) =>
Bot.client.chat.postMessage({
channel: assignee.value?.slackId,
text: `One of your pull requests has been REVIEWED by ${reviewer}! <${url}|View Review> :shrek:`,
Expand Down
18 changes: 18 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
const express = require('express');
const cors = require('cors');
const publishedScheduleRouter = require('./routes/publishedSchedule');

require('dotenv').config();

// routes
const users = require('./routes/users');

const email = require('./routes/nodeMailer');

const app = express();

const catalogRouter = require('./routes/catalog');

const PORT = process.env.PORT || 3001;

app.use(
cors({
origin: `${process.env.REACT_APP_HOST}:${process.env.REACT_APP_PORT}`,
credentials: true,
}),
);

// app.use(cors({ origin: 'http://localhost:3000', credentials: true }));

// add all routes under here
app.use(express.json()); // for req.body
app.use('/published-schedule', publishedScheduleRouter);
app.use('/users', users);
app.use('/catalog', catalogRouter);
app.use('/nodeMailer', email);

app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});
55 changes: 55 additions & 0 deletions common/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// toCamel, isArray, and isObject are helper functions used within utils only
const toCamel = (s) => {
return s.replace(/([-_][a-z])/g, ($1) => {
return $1.toUpperCase().replace('-', '').replace('_', '');
});
};

const isArray = (a) => {
return Array.isArray(a);
};

const isISODate = (str) => {
try {
const ISOString = str.toISOString();
if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(ISOString)) return false;
const d = new Date(ISOString);
return d.toISOString() === ISOString;
} catch (err) {
return false;
}
};

const isObject = (o) => {
return o === Object(o) && !isArray(o) && typeof o !== 'function' && !isISODate(o);
};

// Database columns are in snake case. JavaScript is suppose to be in camel case
// This function converts the keys from the sql query to camel case so it follows JavaScript conventions
const keysToCamel = (data) => {
if (isObject(data)) {
const newData = {};
Object.keys(data).forEach((key) => {
newData[toCamel(key)] = keysToCamel(data[key]);
});
return newData;
}
if (isArray(data)) {
return data.map((i) => {
return keysToCamel(i);
});
}
if (
typeof data === 'string' &&
data.length > 0 &&
data[0] === '{' &&
data[data.length - 1] === '}'
) {
let parsedList = data.replaceAll('"', '');
parsedList = parsedList.slice(1, parsedList.length - 1).split(',');
return parsedList;
}
return data;
};

module.exports = { keysToCamel };
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-prettier": "^4.0.0",
"express": "^4.17.1",
"express-promise-router": "^4.1.1",
"nodemailer": "^6.9.7",
"nodemon": "^2.0.14",
"pg": "^8.8.0",
"pg-promise": "^10.12.1",
"prettier": "^2.4.1"
},
"devDependencies": {
"eslint-config-prettier": "^8.3.0",
"lint-staged": "^11.2.6",
"lint-staged": "^11.2.6",
"husky": "^7.0.4"
"husky": "^7.0.4",
"lint-staged": "^11.2.6"
}
}
93 changes: 93 additions & 0 deletions routes/catalog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const express = require('express');

const { db } = require('../server/db');

const catalogRouter = express.Router();
const { keysToCamel } = require('../common/utils');

// -- GET - Returns all data from the catalog table
catalogRouter.get('/', async (req, res) => {
try {
const allInfo = await db.query(`SELECT * from catalog;`);
res.status(200).json(keysToCamel(allInfo));
} catch (err) {
res.status(500).send(err.message);
}
});

// -- GET/:id - Returns the row that matches the id
catalogRouter.get('/:id', async (req, res) => {
try {
const { id } = req.params;
const allUsers = await db.query(`SELECT * FROM catalog WHERE id = $1;`, [id]);
res.status(200).json(keysToCamel(allUsers));
} catch (err) {
res.status(500).send(err.message);
}
});

// -- POST - Adds a new row to the catalog table
catalogRouter.post('/', async (req, res) => {
const { host, title, eventType, subject, description, year } = req.body;
try {
const returnedData = await db.query(
`INSERT INTO catalog (id, host, title, event_type, subject, description, year)
VALUES (nextval('catalog_id_seq'), $1, $2, $3, $4, $5, $6)
RETURNING id;`,
[host, title, eventType, subject, description, year],
);
res.status(201).json({ id: returnedData[0].id, status: 'Success' });
} catch (err) {
res.status(500).json({
status: 'Failed',
msg: err.message,
});
}
});

// -- PUT - Updates an existing row given an id
// -- All fields are optional
catalogRouter.put('/:id', async (req, res) => {
try {
const { id } = req.params;
const { host, title, eventType, subject, description, year } = req.body;

const updatedCatalog = await db.query(
`UPDATE catalog SET
${host ? 'host = $(host), ' : ''}
${title ? 'title = $(title),' : ''}
${eventType ? 'event_type = $(eventType), ' : ''}
${subject ? 'subject = $(subject), ' : ''}
${description ? 'description = $(description), ' : ''}
${year ? 'year = $(year), ' : ''}
id = '${id}'
WHERE id = '${id}'
RETURNING *;`,
{
host,
title,
eventType,
subject,
description,
year,
id,
},
);
res.status(200).send(keysToCamel(updatedCatalog));
} catch (err) {
res.status(500).send(err.message);
}
});

// -- DELETE - deletes an existing row given an id
catalogRouter.delete('/:id', async (req, res) => {
try {
const { id } = req.params;
const delUser = await db.query(`DELETE FROM catalog WHERE id = $1 RETURNING *;`, [id]);
res.status(200).send(keysToCamel(delUser));
} catch (err) {
res.status(500).send(err.message);
}
});

module.exports = catalogRouter;
37 changes: 37 additions & 0 deletions routes/nodeMailer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const express = require('express');
// const cors = require('cors');
const transporter = require('../transporter');
// TODO: add verifyToken

const emailRouter = express();
// emailRouter.use(
// cors({
// origin: 'http://localhost:3000',
// methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
// credentials: true,
// }),
// );

emailRouter.use(express.json());

emailRouter.post('/send', (req, res) => {
const { email, messageHtml, subject } = req.body;
console.log('req.body', req.body);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint] <no-console> reported by reviewdog 🐶
Unexpected console statement.

console.log('email', email);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint] <no-console> reported by reviewdog 🐶
Unexpected console statement.

const mail = {
from: `${process.env.REACT_APP_EMAIL_FIRST_NAME} ${process.env.REACT_APP_EMAIL_LAST_NAME} ${process.env.REACT_APP_EMAIL_USERNAME}`,
to: email,
subject,
html: messageHtml,
};

transporter.sendMail(mail, (err) => {
if (err) {
res.status(500).send(`Transporter Error: ${err}`);
} else {
res.status(200).send('Transporter Backend Successfully Sent');
}
});
});

module.exports = emailRouter;
Loading
Loading