Skip to content

Commit f0cb8d5

Browse files
Squash
1 parent d4ecdf7 commit f0cb8d5

File tree

95 files changed

+5813
-1054
lines changed

Some content is hidden

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

95 files changed

+5813
-1054
lines changed

.env.sample

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ POSTGRES_DATABASE=
1313
POSTGRES_PASSWORD=
1414
POSTGRES_USER=
1515
SISTEMA_PASSWORD=
16-
SISTEMA_EMAIL_DOMAIN=
16+
SISTEMA_EMAIL_DOMAIN=
17+
CRON_SECRET=

.eslintrc.json

Lines changed: 0 additions & 14 deletions
This file was deleted.

.github/workflows/cron-job.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ name: Send Email Reminders for Missing Lessons
22

33
on:
44
schedule:
5-
- cron: '0 0 * * *' # Runs every day at 00:00 UTC
5+
- cron: '0 0 * * *'
66
workflow_dispatch:
77

88
jobs:
99
call-api:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- name: Log current time
13-
run: date -u # Logs the current UTC time
13+
run: date -u
1414

1515
- name: Call reminders API
16-
run: curl -X GET "${{ secrets.NEXT_PUBLIC_PROD_URL }}/api/reminders"
16+
run: |
17+
curl -X GET "${{ secrets.NEXT_PUBLIC_PROD_URL }}/api/reminders" \
18+
-H "Authorization: Bearer ${{ secrets.CRON_SECRET }}"

README.md

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
1-
# Sistema
1+
# Sistema Tacet
22

3-
## Setup
3+
## Preview
44

5-
- Make sure you have been added to the [UW Blueprint Github Workspace](https://github.com/uwblueprint/).
6-
- Install Docker Desktop ([MacOS](https://docs.docker.com/docker-for-mac/install/) | [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Linux](https://docs.docker.com/engine/install/#server)) and ensure that it is running.
7-
- Install [Node.js](https://nodejs.org/) (v22 tested). It's recommended to use [NVM (Node Version Manager)](https://github.com/nvm-sh/nvm) to manage your Node.js versions.
5+
- Absence Calendar
6+
<img width="1728" alt="image"
7+
src="https://github.com/user-attachments/assets/7b6022b8-48a7-4192-9916-b1c3ef912780"
8+
/>
89

9-
- [Node.js for MacOS](https://nodejs.org/en/download/)
10-
- [Node.js for Windows](https://nodejs.org/en/download/)
11-
- [Node.js for Linux](https://nodejs.org/en/download/package-manager/)
10+
- Admin Dashboard
11+
<img width="1728" alt="image"
12+
src="https://github.com/user-attachments/assets/642d3ff0-dbc0-44f0-80e0-f2fbbecaa916"
13+
/>
14+
15+
## Prerequisites
16+
17+
- If you intend to contribute to this project ensure you have been added to the [UW Blueprint Github Organization](https://github.com/uwblueprint/).
18+
- Install [Node.js](https://nodejs.org/en/download/) (v22 tested). It's recommended to use [NVM (Node Version Manager)](https://github.com/nvm-sh/nvm) to manage your Node.js versions.
19+
- Install Docker Desktop ([MacOS](https://docs.docker.com/desktop/setup/install/mac-install/) | [Windows](https://docs.docker.com/desktop/install/windows-install/) | [Linux](https://docs.docker.com/desktop/setup/install/linux/)) and ensure that it is running.
20+
-
21+
22+
## Clone and Install
1223

1324
- Clone the [Sistema Github Repository](https://github.com/uwblueprint/sistema) to your local machine and `cd` into the project folder:
1425

@@ -34,12 +45,12 @@ npm install
3445
- Build and start the Docker containers
3546

3647
```bash
37-
docker-compose up --build
48+
docker compose up --build
3849
```
3950

4051
## Secrets
4152

42-
- Create A [HashiCorp Cloud Platform Account](https://portal.cloud.hashicorp.com/sign-in?ajs_aid=9085f07d-f411-42b4-855b-72795f4fdbcc&product_intent=vault)
53+
- Create a [HashiCorp Cloud Platform Account](https://portal.cloud.hashicorp.com/sign-in?ajs_aid=9085f07d-f411-42b4-855b-72795f4fdbcc&product_intent=vault)
4354
- Make sure you have been added to the [Sistema HashiCorp Vault](https://github.com/uwblueprint/).
4455
- Install [HashiCorp Vault](https://developer.hashicorp.com/hcp/tutorials/get-started-hcp-vault-secrets/hcp-vault-secrets-install-cli#install-hcp-vault-secrets-cli) in order to pull secrets
4556
- In the folder where you cloned the Sistema repository, log into Vault
@@ -82,22 +93,22 @@ Use the arrow keys to navigate: ↓ ↑ → ←
8293

8394
## Docker Commands
8495

85-
If you’re new to Docker, you can learn more about `docker-compose` commands at
96+
If you’re new to Docker, you can learn more about `docker compose` commands at
8697
this [docker compose overview](https://docs.docker.com/compose/reference/).
8798

8899
```bash
89100
# Start Docker Containers
90-
docker-compose up --build
101+
docker compose up --build
91102
```
92103

93104
```bash
94105
# Stop Containers
95-
docker-compose down
106+
docker compose down
96107
```
97108

98109
```bash
99110
# Remove Containers, Networks, and Volumes:
100-
docker-compose down --volumes
111+
docker compose down --volumes
101112
```
102113

103114
```bash
@@ -157,7 +168,7 @@ This will open an interactive shell inside the container.
157168
## Accessing Database
158169

159170
```bash
160-
# Open a Postgres shell in the sistema-db -1 Docker container and connect to the sistema database
171+
# Open a Postgres shell in the sistema-db-1 Docker container and connect to the sistema database
161172
docker exec -it sistema-db-1 psql -U sistema -d sistema
162173
# Retrieve all rows from the "Absence" table
163174
SELECT * FROM public."Absence";
@@ -267,7 +278,7 @@ git push -f
267278
```
268279

269280
- Commit messages and PR names are descriptive and written in **imperative tense**. The first word should be capitalized. E.g. "Create user REST endpoints", not "Created user REST endpoints"
270-
- PRs can contain multiple commits, they do not need to be squashed together before merging as long as each commit is atomic. Our repo is configured to only allow squash commits to `main` so the entire PR will appear as 1 commit on `main`, but the individual commits are preserved when viewing the PR.
281+
- PRs can contain multiple commits, they do not need to be squashed together before merging as long as each commit is atomic.
271282

272283
## Version Control Guide
273284

app/api/colorGroups/route.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { NextResponse } from 'next/server';
2+
import { prisma } from '@utils/prisma';
3+
4+
export async function GET() {
5+
try {
6+
const colorGroups = await prisma.colorGroup.findMany();
7+
return NextResponse.json(colorGroups);
8+
} catch (error) {
9+
console.error('Error fetching color groups:', error);
10+
return NextResponse.json(
11+
{ error: 'Internal server error' },
12+
{ status: 500 }
13+
);
14+
}
15+
}

app/api/declareAbsence/route.ts

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
1-
import { NextResponse } from 'next/server';
21
import { prisma } from '@utils/prisma';
2+
import { NextResponse } from 'next/server';
33

44
export async function POST(req: Request) {
55
try {
66
const body = await req.json();
7-
console.log(body);
7+
8+
const {
9+
lessonDate,
10+
reasonOfAbsence,
11+
notes,
12+
absentTeacherId,
13+
substituteTeacherId,
14+
locationId,
15+
subjectId,
16+
roomNumber,
17+
lessonPlanFile,
18+
} = body;
819

920
if (
10-
!body.lessonDate ||
11-
!body.reasonOfAbsence ||
12-
!body.absentTeacherId ||
13-
!body.locationId ||
14-
!body.subjectId
21+
!lessonDate ||
22+
!reasonOfAbsence ||
23+
!absentTeacherId ||
24+
!locationId ||
25+
!subjectId
1526
) {
1627
console.log('Missing required fields');
1728
return NextResponse.json(
@@ -23,28 +34,28 @@ export async function POST(req: Request) {
2334
const newAbsence = await prisma.$transaction(async (prisma) => {
2435
let lessonPlanId: number | null = null;
2536

26-
if (body.lessonPlanFile) {
37+
if (lessonPlanFile) {
2738
const lessonPlan = await prisma.lessonPlanFile.create({
2839
data: {
29-
name: body.lessonPlanFile.name,
30-
url: body.lessonPlanFile.url,
31-
size: body.lessonPlanFile.size,
40+
name: lessonPlanFile.name,
41+
url: lessonPlanFile.url,
42+
size: lessonPlanFile.size,
3243
},
3344
});
3445
lessonPlanId = lessonPlan.id;
3546
}
3647

3748
const absence = await prisma.absence.create({
3849
data: {
39-
lessonDate: new Date(body.lessonDate),
50+
lessonDate: new Date(lessonDate),
4051
lessonPlanId,
41-
reasonOfAbsence: body.reasonOfAbsence,
42-
notes: body.notes || null,
43-
absentTeacherId: body.absentTeacherId,
44-
substituteTeacherId: body.substituteTeacherId || null,
45-
locationId: body.locationId,
46-
subjectId: body.subjectId,
47-
roomNumber: body.roomNumber || null,
52+
reasonOfAbsence: reasonOfAbsence,
53+
notes: notes || null,
54+
absentTeacherId: absentTeacherId,
55+
substituteTeacherId: substituteTeacherId || null,
56+
locationId: locationId,
57+
subjectId: subjectId,
58+
roomNumber: roomNumber || null,
4859
},
4960
});
5061

app/api/editAbsence/route.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { prisma } from '@utils/prisma';
2+
import { NextResponse } from 'next/server';
3+
4+
export async function PUT(req: Request) {
5+
try {
6+
const body = await req.json();
7+
const { id, lessonPlanFile, ...fields } = body;
8+
9+
if (!id) {
10+
return NextResponse.json(
11+
{ error: 'Missing absence ID' },
12+
{ status: 400 }
13+
);
14+
}
15+
16+
const updatedAbsence = await prisma.$transaction(async (tx) => {
17+
const existing = await tx.absence.findUnique({
18+
where: { id },
19+
include: { lessonPlan: true },
20+
});
21+
22+
if (!existing) {
23+
throw new Error(`Absence with ID ${id} not found.`);
24+
}
25+
26+
const dataToUpdate: any = {};
27+
28+
if ('lessonDate' in fields)
29+
dataToUpdate.lessonDate = new Date(fields.lessonDate);
30+
if ('reasonOfAbsence' in fields)
31+
dataToUpdate.reasonOfAbsence = fields.reasonOfAbsence;
32+
if ('notes' in fields) dataToUpdate.notes = fields.notes || null;
33+
if ('absentTeacherId' in fields)
34+
dataToUpdate.absentTeacherId = fields.absentTeacherId;
35+
if ('substituteTeacherId' in fields)
36+
dataToUpdate.substituteTeacherId = fields.substituteTeacherId || null;
37+
if ('locationId' in fields) dataToUpdate.locationId = fields.locationId;
38+
if ('subjectId' in fields) dataToUpdate.subjectId = fields.subjectId;
39+
if ('roomNumber' in fields)
40+
dataToUpdate.roomNumber = fields.roomNumber || null;
41+
42+
if (lessonPlanFile) {
43+
if (existing.lessonPlanId) {
44+
await tx.absence.update({
45+
where: { id },
46+
data: { lessonPlanId: null },
47+
});
48+
await tx.lessonPlanFile.delete({
49+
where: { id: existing.lessonPlanId },
50+
});
51+
}
52+
53+
const newLessonPlan = await tx.lessonPlanFile.create({
54+
data: {
55+
name: lessonPlanFile.name,
56+
url: lessonPlanFile.url,
57+
size: lessonPlanFile.size,
58+
},
59+
});
60+
61+
dataToUpdate.lessonPlanId = newLessonPlan.id;
62+
}
63+
64+
const updated = await tx.absence.update({
65+
where: { id },
66+
data: dataToUpdate,
67+
});
68+
69+
return updated;
70+
});
71+
72+
return NextResponse.json(updatedAbsence, { status: 200 });
73+
} catch (err) {
74+
console.error('Error in PUT /api/editAbsence:', err.message || err);
75+
return NextResponse.json(
76+
{ error: 'Internal Server Error', details: err.message },
77+
{ status: 500 }
78+
);
79+
}
80+
}

app/api/filter/locations/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { prisma } from '@utils/prisma';
2-
import { NextRequest, NextResponse } from 'next/server';
32
import { Location } from '@utils/types';
3+
import { NextRequest, NextResponse } from 'next/server';
44

55
export async function GET(req: NextRequest) {
66
try {

app/api/filter/subjects/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { prisma } from '@utils/prisma';
2-
import { NextRequest, NextResponse } from 'next/server';
32
import { SubjectAPI } from '@utils/types';
3+
import { NextRequest, NextResponse } from 'next/server';
44

55
export async function GET(req: NextRequest) {
66
try {

app/api/getAbsenceDates/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { YearlyAbsenceData } from '@utils/types';
12
import { NextResponse } from 'next/server';
23
import { getAbsenceYearRanges } from './absenceDates';
3-
import { YearlyAbsenceData } from '@utils/types';
44

55
export async function GET() {
66
try {

0 commit comments

Comments
 (0)