diff --git a/devU-api/package.json b/devU-api/package.json
index e908de1..9fbe875 100644
--- a/devU-api/package.json
+++ b/devU-api/package.json
@@ -53,7 +53,7 @@
"prettier": "^2.3.0",
"rimraf": "^3.0.2",
"ts-jest": "^27.0.2",
- "ts-node": "^10.0.0",
+ "ts-node": "^10.9.2",
"ts-node-dev": "^2.0.0",
"typescript": "^4.3.2"
},
diff --git a/devU-api/scripts/populate-db.ts b/devU-api/scripts/populate-db.ts
index cdb1b7a..6ed62df 100644
--- a/devU-api/scripts/populate-db.ts
+++ b/devU-api/scripts/populate-db.ts
@@ -55,16 +55,23 @@ async function SendPOST(path: string, requestBody: string | FormData, requesterE
return responseBody
}
-async function CreateCourse(name: string, number: string, semester: string) {
+async function CreateCourse(
+ name: string,
+ number: string,
+ semester: string,
+ isPublic: boolean
+) {
const courseData = {
- name: name,
- semester: semester,
- number: number,
- startDate: '2024-01-24T00:00:00-0500',
- endDate: '2024-05-10T23:59:59-0500',
- }
- console.log('Creating course: ', courseData.name)
- return await SendPOST('/courses/instructor', JSON.stringify(courseData), 'admin')
+ name: name,
+ semester: semester,
+ number: number,
+ startDate: '2024-01-24T00:00:00-0500',
+ endDate: '2024-05-10T23:59:59-0500',
+ is_public: isPublic // Include the public property
+ };
+
+ console.log('Creating course: ', courseData.name);
+ return await SendPOST('/courses/instructor', JSON.stringify(courseData), 'admin');
}
async function joinCourse(courseId: number, userId: number, role: string) {
@@ -208,8 +215,8 @@ async function runCourseAndSubmission() {
const jones = await fetchToken('jones@buffalo.edu', 'jones')
//Create courses
- const courseId1 = (await CreateCourse('Testing Course Name1', 'CSE101', 's2024')).id
- const courseId2 = (await CreateCourse('Testing Course Name2', 'CSE102', 's2024')).id
+ const courseId1 = (await CreateCourse('Testing Course Name1', 'CSE101', 's2024',true)).id
+ const courseId2 = (await CreateCourse('Testing Course Name2', 'CSE102', 's2024',true)).id
//Enroll students
await joinCourse(courseId1, billy, 'student')
diff --git a/devU-api/src/entities/course/course.model.ts b/devU-api/src/entities/course/course.model.ts
index 3ab6c5a..dd657d2 100644
--- a/devU-api/src/entities/course/course.model.ts
+++ b/devU-api/src/entities/course/course.model.ts
@@ -58,4 +58,11 @@ export default class CourseModel {
@DeleteDateColumn({ name: 'deleted_at' })
deletedAt?: Date
+
+ @Column({ type: 'boolean', name: 'is_public', default: false })
+ isPublic: boolean;
+
+ @Column({ name: 'private_data', type: 'timestamp', default: () => 'now()' })
+ private_data?: Date;
+
}
diff --git a/devU-api/src/entities/course/course.serializer.ts b/devU-api/src/entities/course/course.serializer.ts
index 8462cff..7094c1c 100644
--- a/devU-api/src/entities/course/course.serializer.ts
+++ b/devU-api/src/entities/course/course.serializer.ts
@@ -12,5 +12,7 @@ export function serialize(course: CourseModel): Course {
endDate: course.endDate.toISOString(),
createdAt: course.createdAt.toISOString(),
updatedAt: course.updatedAt.toISOString(),
+ isPublic: course.isPublic,
+ private_data: course.private_data ? course.private_data.toISOString() : undefined
}
}
diff --git a/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts b/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts
index f761ab3..332ac2a 100644
--- a/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts
+++ b/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts
@@ -15,6 +15,8 @@ export class addAssignmentsAndCourses1626719306608 implements MigrationInterface
"created_at" TIMESTAMP NOT NULL DEFAULT now(),
"updated_at" TIMESTAMP NOT NULL DEFAULT now(),
"deleted_at" TIMESTAMP,
+ "is_public" boolean NOT NULL DEFAULT false,
+ "private_data" TIMESTAMP NOT NULL DEFAULT now(),
CONSTRAINT "courses_primary_key_constraint" PRIMARY KEY ("id")
)`
)
diff --git a/devU-client/src/components/listItems/courseListItem.tsx b/devU-client/src/components/listItems/courseListItem.tsx
index 368ac2f..db096d6 100644
--- a/devU-client/src/components/listItems/courseListItem.tsx
+++ b/devU-client/src/components/listItems/courseListItem.tsx
@@ -44,7 +44,17 @@ const CourseListItem = ({course, isOpen}: Props) => {
{infoSection("Course Number", course.number)}
{infoSection("Semester", prettyPrintSemester(course.semester))}
{infoSection("Start/End Date", prettyPrintDate(course.startDate), prettyPrintDate(course.endDate))}
+
+ {course && (
+ course.isPublic ? (
+ Public Course
+ ) : (
+ Private Course
+ )
+ )}
+
+
}
)
diff --git a/devU-client/src/components/pages/forms/courses/courseUpdatePage.tsx b/devU-client/src/components/pages/forms/courses/courseUpdatePage.tsx
index 40fbd82..9c81216 100644
--- a/devU-client/src/components/pages/forms/courses/courseUpdatePage.tsx
+++ b/devU-client/src/components/pages/forms/courses/courseUpdatePage.tsx
@@ -44,12 +44,14 @@ const CourseUpdatePage = ({ }) => {
name: '',
number: '',
semester: '',
+ isPublic: false
})
const [startDate, setStartDate] = useState(new Date().toISOString())
const [endDate, setEndDate] = useState(new Date().toISOString())
const [studentEmail, setStudentEmail] = useState("")
const [emails, setEmails] = useState([])
const [invalidFields, setInvalidFields] = useState(new Map())
+ const [privateDate, setPrivateDate] = useState(new Date().toISOString().split("T")[0]);
const { courseId } = useParams() as UrlParams
useEffect(() => {
@@ -60,9 +62,11 @@ const CourseUpdatePage = ({ }) => {
name: res.name,
number: res.number,
semester: res.semester,
+ isPublic: res.isPublic
});
setStartDate(new Date(res.startDate).toISOString().split("T")[0]);
setEndDate(new Date(res.endDate).toISOString().split("T")[0]);
+ setPrivateDate(new Date(res.privateDate).toISOString().split("T")[0]);
isMounted = true;
});
}
@@ -80,10 +84,15 @@ const CourseUpdatePage = ({ }) => {
setFormData(prevState => ({ ...prevState, [key]: value }))
}
}
-
+ const handleCheckboxChange = (e: React.ChangeEvent) => {
+ setFormData(prevState => ({ ...prevState, isPublic: e.target.checked }));
+ };
const handleStartDateChange = (event: React.ChangeEvent) => { setStartDate(event.target.value) }
const handleEndDateChange = (event: React.ChangeEvent) => { setEndDate(event.target.value) }
+ const handlePrivateDateChange = (event: React.ChangeEvent) => {
+ setPrivateDate(event.target.value);
+ };
const handleCourseUpdate = () => {
const finalFormData = {
name: formData.name,
@@ -91,6 +100,8 @@ const CourseUpdatePage = ({ }) => {
semester: formData.semester,
startDate: startDate + "T16:02:41.849Z",
endDate: endDate + "T16:02:41.849Z",
+ isPublic: formData.isPublic,
+ privateDate: privateDate + "T16:02:41.849Z",
}
RequestService.put(`/api/courses/${courseId}`, finalFormData)
@@ -299,6 +310,20 @@ const CourseUpdatePage = ({ }) => {
+
+
+
+
+
+
+
diff --git a/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx b/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx
index e5814ce..ca101c8 100644
--- a/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx
+++ b/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx
@@ -1,102 +1,131 @@
-import React, { useState } from 'react'
-import { useHistory } from 'react-router-dom'
-import { ExpressValidationError } from 'devu-shared-modules'
-
-import PageWrapper from 'components/shared/layouts/pageWrapper'
-
-import RequestService from 'services/request.service'
-
-import { useActionless } from 'redux/hooks'
-import TextField from 'components/shared/inputs/textField'
-import { SET_ALERT } from 'redux/types/active.types'
-import formStyles from './coursesFormPage.scss'
-import { applyMessageToErrorFields, removeClassFromField } from "../../../../utils/textField.utils";
-
+import React, { useState } from 'react';
+import { useHistory } from 'react-router-dom';
+import RequestService from 'services/request.service';
+import { useActionless } from 'redux/hooks';
+import TextField from 'components/shared/inputs/textField';
+import { SET_ALERT } from 'redux/types/active.types';
+import formStyles from './coursesFormPage.scss';
+import PageWrapper from 'components/shared/layouts/pageWrapper';
const EditCourseFormPage = () => {
- const [setAlert] = useActionless(SET_ALERT)
+ const [setAlert] = useActionless(SET_ALERT);
const history = useHistory();
const [formData, setFormData] = useState({
name: '',
number: '',
semester: '',
- })
+ isPublic: false
+ });
- const [startDate, setStartDate] = useState(new Date().toISOString().split("T")[0])
- const [endDate, setEndDate] = useState(new Date().toISOString().split("T")[0])
- const [invalidFields, setInvalidFields] = useState(new Map
())
+ const [startDate, setStartDate] = useState(new Date().toISOString().split("T")[0]);
+ const [endDate, setEndDate] = useState(new Date().toISOString().split("T")[0]);
+ const [privateDate, setPrivateDate] = useState(new Date().toISOString().split("T")[0]);
- const handleChange = (value: String, e: React.ChangeEvent) => {
- const key = e.target.id
- setFormData(prevState => ({ ...prevState, [key]: value }))
+ const handleChange = (value: string, e: React.ChangeEvent) => {
+ const key = e.target.id;
+ setFormData(prevState => ({ ...prevState, [key]: value }));
+ };
- const newInvalidFields = removeClassFromField(invalidFields, key)
- setInvalidFields(newInvalidFields)
- }
+ const handleCheckboxChange = (e: React.ChangeEvent) => {
+ setFormData(prevState => ({ ...prevState, isPublic: e.target.checked }));
+ };
- const handleStartDateChange = (event: React.ChangeEvent) => { setStartDate(event.target.value) }
- const handleEndDateChange = (event: React.ChangeEvent) => { setEndDate(event.target.value) }
+ const handleStartDateChange = (event: React.ChangeEvent) => {
+ setStartDate(event.target.value);
+ };
+ const handleEndDateChange = (event: React.ChangeEvent) => {
+ setEndDate(event.target.value);
+ };
+
+ const handlePrivateDateChange = (event: React.ChangeEvent) => {
+ setPrivateDate(event.target.value);
+ };
+
+ const formatDateForSubmission = (date: string) => {
+ return new Date(date).toISOString();
+ };
+
+ const isFormValid = () => {
+ return formData.name && formData.number && formData.semester && startDate && endDate;
+ };
const handleSubmit = () => {
const finalFormData = {
name: formData.name,
number: formData.number,
semester: formData.semester,
- startDate: startDate + "T16:02:41.849Z",
- endDate: endDate + "T16:02:41.849Z",
- }
+ startDate: formatDateForSubmission(startDate),
+ endDate: formatDateForSubmission(endDate),
+ isPublic: formData.isPublic,
+ privateDate: formatDateForSubmission(privateDate)
+ };
RequestService.post('/api/courses/instructor', finalFormData)
.then(() => {
- setAlert({ autoDelete: true, type: 'success', message: 'Course Added' })
- history.goBack()
+ setAlert({ autoDelete: true, type: 'success', message: 'Course Added' });
+ history.goBack();
})
- .catch((err: ExpressValidationError[] | Error) => {
- const message = Array.isArray(err) ? err.map((e) => `${e.param} ${e.msg}`).join(', ') : err.message
-
- const newFields = new Map()
- Array.isArray(err) ? err.map((e) => applyMessageToErrorFields(newFields, e.param, e.msg)) : newFields
- setInvalidFields(newFields);
- setAlert({ autoDelete: false, type: 'error', message })
- })
- .finally(() => {
- })
- }
+ .catch((err) => {
+ setAlert({ autoDelete: false, type: 'error', message: err.message });
+ });
+ };
return (
Create Course
-
-
-
-
+
+
+
-
+
-
+
+
-
+
- )
-
-}
-
+ );
+};
-export default EditCourseFormPage
\ No newline at end of file
+export default EditCourseFormPage;
\ No newline at end of file
diff --git a/devU-shared/src/types/course.types.ts b/devU-shared/src/types/course.types.ts
index 0e03d98..cc21135 100644
--- a/devU-shared/src/types/course.types.ts
+++ b/devU-shared/src/types/course.types.ts
@@ -7,4 +7,8 @@ export type Course = {
endDate: string
createdAt?: string
updatedAt?: string
+ isPublic?: boolean;
+ private_data?: string;
+ allowlist?: string[];
+ blocklist?: string[];
}