Skip to content

Commit c4cba9d

Browse files
committed
Merge branch 'develop' into #2137-attendance-tracker-tool
2 parents d2b0f48 + c70c875 commit c4cba9d

128 files changed

Lines changed: 4979 additions & 434 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/run-tests.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@ jobs:
2727
with:
2828
node-version: 18.17.1
2929
cache: 'yarn'
30+
- name: Add Env Variables
31+
run: cd src/backend && echo "DATABASE_URL=\"postgresql://postgres:docker@localhost:5432/nerpm?schema=public\"" >> .env
32+
- name: Pull Docker Image
33+
run: docker run --name finishline -e POSTGRES_PASSWORD=docker -p 5432:5432 -d postgres
34+
- name: Wait for Postgres to start
35+
run: sleep 10s
36+
- name: Create Database
37+
run: docker exec finishline psql -U postgres -c "CREATE DATABASE nerpm;"
3038
- name: Install modules
31-
run: yarn install && yarn prisma:generate
39+
run: yarn install && yarn prisma:generate && yarn prisma:migrate:prod
3240
- name: Run tests
3341
run: yarn test:backend; yarn test:frontend
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Send Task Deadline Notifications
2+
3+
on:
4+
schedule:
5+
- cron: '0 9 * * *'
6+
7+
jobs:
8+
send_notifications:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Send notifications
12+
run: |
13+
curl -X POST https://api.finishlinebyner.com/notifications/task-deadlines \
14+
-H 'Authorization: ${{ secrets.NOTIFICATION_ENDPOINT_SECRET }}'

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"test:frontend": "yarn workspace shared build; yarn workspace frontend test",
2626
"test:backend": "yarn workspace shared build; yarn workspace backend test",
2727
"test": "yarn test:backend && yarn test:frontend",
28+
"test:setup": "echo 'DATABASE_URL=\"postgresql://postgres:docker@localhost:5433/nerpm?schema=public\"' >> src/backend/.env && docker run --name finishline_test -e POSTGRES_PASSWORD=docker -p 5433:5432 -d postgres && sleep 5 && docker exec finishline_test psql -U postgres -c \"CREATE DATABASE nerpm;\" && yarn prisma:migrate:prod",
29+
"test:teardown": "docker stop finishline_test && docker rm finishline_test && echo 'DATABASE_URL=\"postgresql://postgres:docker@localhost:5432/nerpm?schema=public\"' >> src/backend/.env",
2830
"build": "yarn run build:backend && yarn run build:shared && yarn run build:frontend",
2931
"build:backend": "yarn workspace backend build",
3032
"build:shared": "yarn workspace shared build",

src/backend/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import changeRequestsRouter from './src/routes/change-requests.routes';
1111
import descriptionBulletsRouter from './src/routes/description-bullets.routes';
1212
import tasksRouter from './src/routes/tasks.routes';
1313
import reimbursementRequestsRouter from './src/routes/reimbursement-requests.routes';
14+
import notificationsRouter from './src/routes/notifications.routes';
15+
import designReviewsRouter from './src/routes/design-reviews.routes';
1416

1517
const app = express();
1618
const port = process.env.PORT || 3001;
@@ -52,6 +54,8 @@ app.use('/change-requests', changeRequestsRouter);
5254
app.use('/description-bullets', descriptionBulletsRouter);
5355
app.use('/tasks', tasksRouter);
5456
app.use('/reimbursement-requests', reimbursementRequestsRouter);
57+
app.use('/design-reviews', designReviewsRouter);
58+
app.use('/notifications', notificationsRouter);
5559
app.use('/', (_req, res) => {
5660
res.json('Welcome to FinishLine');
5761
});

src/backend/src/controllers/design-review.controllers.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { NextFunction, Request, Response } from 'express';
2+
import DesignReviewsService from '../services/design-reviews.services';
3+
import { getCurrentUser } from '../utils/auth.utils';
4+
import { User } from '@prisma/client';
5+
6+
export default class DesignReviewsController {
7+
static async getAllDesignReviews(_req: Request, res: Response, next: NextFunction) {
8+
try {
9+
const designReviews = await DesignReviewsService.getAllDesignReviews();
10+
return res.status(200).json(designReviews);
11+
} catch (error: unknown) {
12+
next(error);
13+
}
14+
}
15+
16+
static async deleteDesignReview(req: Request, res: Response, next: NextFunction) {
17+
try {
18+
const drId: string = req.params.designReviewId;
19+
const user: User = await getCurrentUser(res);
20+
const deletedDesignReview = await DesignReviewsService.deleteDesignReview(user, drId);
21+
return res.status(200).json(deletedDesignReview);
22+
} catch (error: unknown) {
23+
next(error);
24+
}
25+
}
26+
27+
static async createDesignReview(req: Request, res: Response, next: NextFunction) {
28+
try {
29+
const submitter: User = await getCurrentUser(res);
30+
const {
31+
dateScheduled,
32+
teamTypeId,
33+
requiredMemberIds,
34+
optionalMemberIds,
35+
location,
36+
isOnline,
37+
isInPerson,
38+
zoomLink,
39+
docTemplateLink,
40+
wbsNum,
41+
meetingTimes
42+
} = req.body;
43+
44+
const createdDesignReview = await DesignReviewsService.createDesignReview(
45+
submitter,
46+
dateScheduled,
47+
teamTypeId,
48+
requiredMemberIds,
49+
optionalMemberIds,
50+
isOnline,
51+
isInPerson,
52+
docTemplateLink,
53+
wbsNum,
54+
meetingTimes,
55+
zoomLink,
56+
location
57+
);
58+
return res.status(200).json(createdDesignReview);
59+
} catch (error: unknown) {
60+
next(error);
61+
}
62+
}
63+
64+
static async getSingleDesignReview(req: Request, res: Response, next: NextFunction) {
65+
try {
66+
const drId: string = req.params.designReviewId;
67+
const user: User = await getCurrentUser(res);
68+
const designReview = await DesignReviewsService.getSingleDesignReview(user, drId);
69+
return res.status(200).json(designReview);
70+
} catch (error: unknown) {
71+
next(error);
72+
}
73+
}
74+
75+
// Edit a work package to the given specifications
76+
static async editDesignReviews(req: Request, res: Response, next: NextFunction) {
77+
try {
78+
const {
79+
dateScheduled,
80+
teamType,
81+
requiredMembers,
82+
optionalMembers,
83+
isOnline,
84+
isInPerson,
85+
zoomLink,
86+
location,
87+
docTemplateLink,
88+
status,
89+
attendees,
90+
meetingTimes
91+
} = req.body;
92+
93+
const { designReviewId } = req.params;
94+
95+
// get the user from the submitter
96+
const user = await getCurrentUser(res);
97+
98+
await DesignReviewsService.editDesignReview(
99+
user,
100+
designReviewId,
101+
dateScheduled,
102+
teamType.teamTypeId,
103+
requiredMembers,
104+
optionalMembers,
105+
isOnline,
106+
isInPerson,
107+
zoomLink,
108+
location,
109+
docTemplateLink,
110+
status,
111+
attendees,
112+
meetingTimes
113+
);
114+
return res.status(200).json({ message: 'Design Review updated successfully' });
115+
} catch (error: unknown) {
116+
next(error);
117+
}
118+
}
119+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { NextFunction, Request, Response } from 'express';
2+
import NotificationsService from '../services/notifications.services';
3+
4+
export default class NotificationsController {
5+
static async sendTaskDeadlineSlackNotifications(_req: Request, res: Response, next: NextFunction) {
6+
try {
7+
await NotificationsService.sendTaskDeadlineSlackNotifications();
8+
9+
res.status(200).json({ message: 'Successfully sent task deadline notifications!' });
10+
} catch (error: unknown) {
11+
next(error);
12+
}
13+
}
14+
}

src/backend/src/controllers/users.controllers.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,33 @@ export default class UsersController {
145145
next(error);
146146
}
147147
}
148+
149+
static async setUserScheduleSettings(req: Request, res: Response, next: NextFunction) {
150+
try {
151+
const { personalGmail, personalZoomLink, availability } = req.body;
152+
const user = await getCurrentUser(res);
153+
154+
const updatedScheduleSettings = await UsersService.setUserScheduleSettings(
155+
user,
156+
personalGmail,
157+
personalZoomLink,
158+
availability
159+
);
160+
161+
return res.status(200).json(updatedScheduleSettings);
162+
} catch (error: unknown) {
163+
next(error);
164+
}
165+
}
166+
167+
static async getUserScheduleSettings(req: Request, res: Response, next: NextFunction) {
168+
try {
169+
const userId: number = parseInt(req.params.userId);
170+
const submitter = await getCurrentUser(res);
171+
const userScheduleSettings = await UsersService.getUserScheduleSettings(userId, submitter);
172+
res.status(200).json(userScheduleSettings);
173+
} catch (error: unknown) {
174+
next(error);
175+
}
176+
}
148177
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Prisma } from '@prisma/client';
2+
3+
const designReviewQueryArgs = Prisma.validator<Prisma.Design_ReviewArgs>()({
4+
include: {
5+
userCreated: true,
6+
teamType: true,
7+
requiredMembers: true,
8+
optionalMembers: true,
9+
confirmedMembers: true,
10+
deniedMembers: true,
11+
attendees: true,
12+
userDeleted: true,
13+
wbsElement: true
14+
}
15+
});
16+
17+
export default designReviewQueryArgs;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
Warnings:
3+
4+
- A unique constraint covering the columns `[identifier]` on the table `Reimbursement_Request` will be added. If there are existing duplicate values, this will fail.
5+
6+
*/
7+
-- Select all old RRs that has no identifier in dateCreated ascending order
8+
CREATE TEMP TABLE cte_table AS (
9+
WITH CTE AS (
10+
SELECT
11+
"reimbursementRequestId",
12+
row_number() OVER (ORDER BY "dateCreated" ASC, "reimbursementRequestId" ASC) AS new_identifier
13+
FROM
14+
"Reimbursement_Request"
15+
)
16+
SELECT * FROM CTE
17+
);
18+
19+
-- AlterTable
20+
ALTER TABLE "Reimbursement_Request" ADD COLUMN "identifier" SERIAL NOT NULL;
21+
22+
-- Assign Identifier to all old Reimbursement Requests based on their dateCreated order
23+
UPDATE "Reimbursement_Request" AS rr
24+
SET "identifier" = "cte_table".new_identifier
25+
FROM cte_table
26+
WHERE rr."reimbursementRequestId" = "cte_table"."reimbursementRequestId";
27+
28+
-- CreateIndex
29+
CREATE UNIQUE INDEX "Reimbursement_Request_identifier_key" ON "Reimbursement_Request"("identifier");
30+
31+
-- Remove the temporary table
32+
DROP TABLE cte_table;

0 commit comments

Comments
 (0)