Skip to content
Open

Dev #23

Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion backend/alembic/versions/001_initial_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ def downgrade() -> None:
op.drop_table("sections")
op.drop_table("students")
op.drop_table("instructors")
op.drop_table("time_blocks")
op.drop_table("time_blocks")
55 changes: 55 additions & 0 deletions backend/alembic/versions/002_initial_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""initial schema

Revision ID: 002
Revises:
Create Date: 2026-05-06

"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

revision: str = "002"
down_revision: Union[str, None] = "001"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# Drop the old FK constraint
op.drop_constraint(
"sections_instructor_id_fkey",
"sections",
type_="foreignkey"
)

# Create the new FK with CASCADE
op.create_foreign_key(
None, # Let Alembic generate a name
"sections", # Source table
"instructors", # Referenced table
["instructor_id"], # Local column
["id"], # Remote column
ondelete="CASCADE"
)


def downgrade() -> None:
# Reverse the change: drop CASCADE FK
op.drop_constraint(
None,
"sections",
type_="foreignkey"
)

# Restore original FK without CASCADE
op.create_foreign_key(
"sections_instructor_id_fkey",
"sections",
"instructors",
["instructor_id"],
["id"]
)
4 changes: 2 additions & 2 deletions backend/stp_scheduler/db/models/association.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
student_section_table = Table(
"student_sections",
Base.metadata,
Column("student_id", String, ForeignKey("students.id"), primary_key=True),
Column("section_id", String, ForeignKey("sections.id"), primary_key=True),
Column("student_id", String, ForeignKey("students.id", ondelete="CASCADE"), primary_key=True),
Column("section_id", String, ForeignKey("sections.id", ondelete="CASCADE"), primary_key=True),
)
2 changes: 1 addition & 1 deletion backend/stp_scheduler/db/models/section.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ class SectionRow(Base):
)
days: Mapped[str | None] = mapped_column(String, nullable=True)
instructor_id: Mapped[str | None] = mapped_column(
String, ForeignKey("instructors.id"), nullable=True
String, ForeignKey("instructors.id", ondelete="SET NULL"), nullable=True
)
2 changes: 1 addition & 1 deletion frontend/app/Components/InputPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export default function InputPage({ path }: InputPageProps) {
></EditStudent>
<EditTeacher sections={section_data} teachers={instructor_data}></EditTeacher>
<DeleteStudent students={student_data}></DeleteStudent>
<DeleteTeacher></DeleteTeacher>
<DeleteTeacher instructors={instructor_data}></DeleteTeacher>
</div>
);
}
6 changes: 4 additions & 2 deletions frontend/app/Components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,19 @@ export default function Navbar(){
<div className={"flex justify-end p-3 pt-5 pb-5 mb-2 border-b-2 bg-[#f76902] text-white pr-5 items-center"}>
<div className="w-full justify-start pl-8 p-2 text-2xl font-bold"><a href="/">Student Transition Program Scheduler</a></div>

<div className="hidden md:visible md:inline-flex p-1 pl-4 pr-4 border-2 rounded">
<NavbarAuthControls/>

<div className="hidden md:visible md:inline-flex mx-4 p-1 pl-4 pr-4 border-2 rounded">
<ul className="inline-flex flex-row flex-nowrap justify-between text-center text-base">
{navItems.map((navItem, index) => (
<li className="flex flex-row justify-center items-center" key={index}>
| {<NavItem key={index} {...navItem} />}
</li>
))}
<li className="flex flex-row justify-center items-center">|</li>
<li className="flex flex-row justify-center items-center"><NavbarAuthControls/> |</li>
</ul>
</div>

</div>
);
}
11 changes: 5 additions & 6 deletions frontend/app/Components/NavbarAuthControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import Link from "next/link";
import { useEffect, useState } from "react";
import { API_URL, getToken, setToken } from "../apiClient";
import NavItem from "./Navitem";

export default function NavbarAuthControls() {
const [loggedIn, setLoggedIn] = useState(false);
Expand Down Expand Up @@ -38,20 +39,18 @@ export default function NavbarAuthControls() {
}

return (
<li className="flex flex-row justify-center items-center list-none">
<div className="flex flex-row justify-center items-center underline w-44 p-1 text-center border-2 rounded ">
{loggedIn ? (
<button
type="button"
onClick={signOut}
className="underline ml-1 bg-transparent border-0 cursor-pointer text-inherit font-inherit"
className="underline ml-1 p-2 pl-4 pr-4 bg-transparent border-0 cursor-pointer text-inherit font-inherit"
>
Sign out
</button>
) : (
<Link href="/login" className="underline ml-1">
Sign in
</Link>
<NavItem title="Sign in" route="/login" ></NavItem>
)}
</li>
</div>
);
}
2 changes: 1 addition & 1 deletion frontend/app/Cruds/deleteStudent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function DeleteStudent({students}: DeleteStudentProps){

// TODO: update delete student in the API to do this because the file should not be responsible for re-updating data
// Reload students without the deleted student
getFromBackendApi("Students");
// getFromBackendApi("Students");
}

return (
Expand Down
21 changes: 12 additions & 9 deletions frontend/app/Cruds/deleteTeacher.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { FormEvent, useEffect, useState } from "react";
import * as API from "../SendToApi";
import { getFromBackendApi, instructor_data } from "../GetFromApi";
import { getFromBackendApi } from "../GetFromApi";
import type { InstructorProps } from "../InstructorProps";

export default function DeleteTeacher() {
interface DeleteInstructorProps{
instructors: InstructorProps[];
}
export default function DeleteTeacher({instructors}: DeleteInstructorProps) {
const [instructorId, setInstructorId] = useState<string>("");
const [instructors, setInstructors] = useState<InstructorProps[]>([]);

/**
* Delete an instructor
*
* @param e FormEvent<HTMLFormElement>
*/
function deleteInstructorHandler(e: FormEvent<HTMLFormElement>) {
e.preventDefault();

Expand All @@ -15,14 +22,10 @@ export default function DeleteTeacher() {
e.currentTarget.reset();
setInstructorId("");

getFromBackendApi("Instructors");
setInstructors(instructor_data);
// TODO: update delete instructor in the API to do this because the file should not be responsible for re-updating data
// getFromBackendApi("Instructors");
}

useEffect(() => {
setInstructors(instructor_data);
}, []);

return (
<details className="mb-2">
<summary className="hover:backdrop-brightness-125 p-4">
Expand Down
17 changes: 13 additions & 4 deletions frontend/app/GetFromApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ export function setSectionIds(ids: any) {
section_ids = ids;
}

/**
* Calls getFromBackendApi("Instructors"), getFromBackendApi("Students"), and getFromBackendApi("Sections")
*/
export async function getAll() {
getFromBackendApi("Instructors")
getFromBackendApi("Students")
getFromBackendApi("Sections")
}

/**
* Fetches data from the backend. Use type "Instructors", "Students", or "Sections".
*/
Expand All @@ -45,16 +54,16 @@ export async function getFromBackendApi(type: string) {
const result = await response.json();
console.log(result);

switch (type) {
case "Instructors":
switch (type.toLowerCase()) {
case "instructors":
instructor_data = result;
return;

case "Students":
case "students":
student_data = result;
return;

case "Sections":
case "sections":
var ids: string[] = [];
result.forEach((element: Record<string, any>) => {
ids.push(element.id);
Expand Down
17 changes: 17 additions & 0 deletions frontend/app/SendToApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
*/

import { apiFetch } from "./apiClient";
import { getFromBackendApi } from "./GetFromApi";

export function generateId() {
return "fake-id";
}

/**
* POST /csv/update
* @param csvData the data the backend will update with
* @returns
*/
export function updateFromCSV(csvData: any) {
try {
var result: any;
Expand All @@ -33,6 +39,10 @@ export function updateFromCSV(csvData: any) {
}
}

/**
* POST /schedule/regenerate
* @returns
*/
export function regenerateSchedule() {
try {
var result: any;
Expand Down Expand Up @@ -87,6 +97,7 @@ export function createInstructor(instructor: InstructorModel) {

apiFetch(`/instructors/create`, requestOptions)
.then((response) => response.json())
.then(() => getFromBackendApi("Instructors"))
.then((data) => (result = data));

return result;
Expand All @@ -102,6 +113,7 @@ export function editInstructor(instructor: any) {

apiFetch(`/instructors/update`, requestOptions)
.then((response) => response.json())
.then(() => getFromBackendApi("Instructors"))
.then((data) => (result = data));

return result;
Expand All @@ -119,6 +131,7 @@ export function deleteInstructor(instructor_id: string) {
requestOptions,
)
.then((response) => response.json())
.then(() => getFromBackendApi("Instructors"))
.then((data) => (result = data));

return result;
Expand Down Expand Up @@ -150,6 +163,7 @@ export function createStudent(student: StudentModel) {

apiFetch(`/students/create`, requestOptions)
.then((response) => response.json())
.then(() => getFromBackendApi("Students"))
.then((data) => (result = data));

return result;
Expand All @@ -166,6 +180,7 @@ export function editStudent(student: any) {

apiFetch(`/students/update`, requestOptions)
.then((response) => response.json())
.then(() => getFromBackendApi("Students"))
.then((data) => (result = data));

return result;
Expand All @@ -181,6 +196,7 @@ export function deleteStudent(student_id: string) {

apiFetch(`/students/delete?student_id=${encodeURIComponent(student_id)}`, requestOptions)
.then((response) => response.json())
.then(() => getFromBackendApi("Students"))
.then((data) => (result = data));

return result;
Expand All @@ -197,6 +213,7 @@ export function createSection(section: string) {

apiFetch(`/create/section`, requestOptions)
.then((response) => response.json())
.then(() => getFromBackendApi("Sections"))
.then((data) => (result = data));

return result;
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default function LoginPage() {
}

return (
<main className="max-w-sm mx-auto mt-16 px-4 pb-16">
<main className="max-w-lg mx-auto my-[13.25vh] px-16 py-16 border-2 border-black rounded-4xl">
<h1 className="text-xl font-semibold mb-4 text-black">Sign in</h1>
<p className="text-sm text-neutral-700 mb-4">
Use the username and password matching AUTH_USERNAME and AUTH_PASSWORD on
Expand Down