Skip to content

Commit

Permalink
Merge branch 'dev' into 65-final-catalog-adjustments-backend
Browse files Browse the repository at this point in the history
  • Loading branch information
michellelin1 authored Apr 30, 2024
2 parents 077eed1 + 3b645a8 commit 2f24834
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 15 deletions.
25 changes: 19 additions & 6 deletions routes/day.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,25 @@ dayRouter.get('/:id', async (req, res) => {
dayRouter.post('/', async (req, res) => {
try {
const { eventDate, location, notes } = req.body;
const inUse = await db.query(`SELECT * FROM day WHERE event_date = $1;`, [eventDate]);
if (inUse.length) {
res.status(201).json({
status: 'Failed',
message: 'Day already exists',
});
const existingDay = await db.query(`SELECT * FROM day WHERE event_date = $1;`, [eventDate]);
if (existingDay.length) {
// day exists but has no events --> update location + notes return existing day_id
if (existingDay[0].day_count === 0) {
await db.query(`UPDATE day SET location = $1, notes = $2 WHERE id = $3;`, [
location,
notes,
existingDay[0].id,
]);
res.status(201).json({
status: 'Success',
id: existingDay[0].id,
});
} else {
res.status(201).json({
status: 'Failed',
message: 'Day already exists',
});
}
return;
}

Expand Down
50 changes: 50 additions & 0 deletions routes/publishedSchedule.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,56 @@ publishedScheduleRouter.get('/season', async (req, res) => {
}
});

// GET /published-schedule/stats - returns stats of event types and subjects for a specific season
publishedScheduleRouter.get('/stats', async (req, res) => {
try {
const { season, year } = req.query;

const statResult = await db.query(
`
WITH all_event_types AS (
SELECT DISTINCT unnest(event_type) AS event_type
FROM catalog
),
all_subjects AS (
SELECT DISTINCT unnest(subject) AS subject
FROM catalog
),
all_permutations AS (
SELECT aet.event_type, asu.subject
FROM all_event_types aet
CROSS JOIN all_subjects asu
)
SELECT
COALESCE(ap.event_type::text, 'Total') AS event_type,
COALESCE(ap.subject::text, 'Total') AS subject,
COALESCE(COUNT(c.catalog_id), 0) AS total_count
FROM all_permutations ap
LEFT JOIN (
SELECT *,
ps.day_id AS ps_day_id,
c.id AS catalog_id
FROM catalog c
JOIN published_schedule ps ON c.id = ps.event_id
JOIN day d ON PS.day_id = d.id
WHERE $1 = ANY(c.season)
AND EXTRACT(YEAR FROM d.event_date) = $2
) c ON ap.event_type = ANY(c.event_type) AND ap.subject = ANY(c.subject)
GROUP BY ROLLUP (ap.event_type), ROLLUP (ap.subject)
ORDER BY CASE WHEN ap.event_type IS NULL THEN 1 ELSE 0 END,
CASE WHEN ap.subject IS NULL THEN 1 ELSE 0 END,
ap.event_type NULLS FIRST,
ap.subject NULLS FIRST;
`,
[season, year],
);

res.status(200).json(keysToCamel(statResult));
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});

// GET /published-schedule/date - returns all events occurring on a specific date
publishedScheduleRouter.get('/dayId', async (req, res) => {
try {
Expand Down
50 changes: 42 additions & 8 deletions routes/users.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const express = require('express');
const { keysToCamel } = require('../common/utils');
const { keysToCamel, isInteger } = require('../common/utils');
const { db } = require('../server/db');

const userRouter = express.Router();
Expand All @@ -17,9 +17,14 @@ userRouter.get('/', async (req, res) => {

userRouter.get('/pending-accounts', async (req, res) => {
try {
const pendingAccounts = await db.query(
`SELECT * FROM users WHERE approved = FALSE ORDER BY first_name ASC;`,
);
const { accountType } = req.query;
let queryString = 'SELECT * FROM users WHERE approved = FALSE ';
if (accountType === 'admin') {
queryString += `AND type = 'admin'`;
} else if (accountType === 'student') {
queryString += `AND type = 'student'`;
}
const pendingAccounts = await db.query(`${queryString} ORDER BY first_name ASC;`);
res.status(200).json(keysToCamel(pendingAccounts));
} catch (err) {
res.status(500).send(err.message);
Expand All @@ -28,10 +33,39 @@ userRouter.get('/pending-accounts', async (req, res) => {

userRouter.get('/approved-accounts', async (req, res) => {
try {
const pendingAccounts = await db.query(
`SELECT * FROM users WHERE approved = TRUE ORDER BY first_name ASC;`,
);
res.status(200).json(keysToCamel(pendingAccounts));
const { keyword, accountType } = req.query;
let { page, limit } = req.query;
page = isInteger(page) ? parseInt(page, 10) : 1;
limit = isInteger(limit) ? parseInt(limit, 10) : 10;
const offset = (page - 1) * limit;
let queryString = 'FROM users WHERE approved = TRUE ';
if (accountType === 'admin') {
queryString += `AND type = 'admin'`;
} else if (accountType === 'student') {
queryString += `AND type = 'student'`;
}
let approvedAccounts;
let userCount;
let params = [];
if (keyword) {
params = [`%${keyword}%`, `%${keyword}%`, `%${keyword}%`, `%${keyword}%`, limit, offset];
approvedAccounts = await db.query(
`SELECT * ${queryString} AND (first_name ILIKE $1 OR last_name ILIKE $2 OR email ILIKE $3 OR CONCAT(first_name, ' ', last_name) ILIKE $4) ORDER BY first_name ASC LIMIT $5 OFFSET $6;`,
params,
);
userCount = await db.query(
`SELECT COUNT(*) ${queryString} AND (first_name ILIKE $1 OR last_name ILIKE $2 OR email ILIKE $3 OR CONCAT(first_name, ' ', last_name) ILIKE $4);`,
params,
);
} else {
params = [limit, offset];
approvedAccounts = await db.query(
`SELECT * ${queryString} ORDER BY first_name ASC LIMIT $1 OFFSET $2;`,
params,
);
userCount = await db.query(`SELECT COUNT(*) ${queryString};`, params);
}
res.status(200).json(keysToCamel({ accounts: approvedAccounts, count: userCount }));
} catch (err) {
res.status(500).send(err.message);
}
Expand Down
2 changes: 1 addition & 1 deletion server/schema/catalog.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CREATE TYPE event AS ENUM ('guest speaker', 'study-trip', 'workshop', 'other');
CREATE TYPE subject AS ENUM ('life skills', 'science', 'technology', 'engineering', 'math', 'college readiness');
CREATE TYPE year AS ENUM ('junior', 'senior', 'both');
CREATE TYPE year AS ENUM ('junior', 'senior');
CREATE TYPE season AS ENUM ('spring', 'summer', 'fall');

DROP TABLE IF EXISTS catalog;
Expand Down

0 comments on commit 2f24834

Please sign in to comment.