From 74a59a2835638ca06e1b7d00f81c60fb7d7c0abc Mon Sep 17 00:00:00 2001 From: ashwaqaljanahi2021 Date: Tue, 5 Nov 2024 13:12:12 -0500 Subject: [PATCH 1/2] added ability to check if course is public --- devU-api/package.json | 2 +- devU-api/scripts/populate-db.ts | 29 ++-- devU-api/src/entities/course/course.model.ts | 3 + .../src/entities/course/course.serializer.ts | 1 + .../1626719306608-addAssignmentsAndCourses.ts | 1 + ...2-addAssignmentsAndCourses1626719306608.ts | 14 ++ .../components/listItems/courseListItem.tsx | 10 ++ .../pages/forms/courses/coursesFormPage.tsx | 137 ++++++++++-------- devU-shared/src/types/course.types.ts | 4 + 9 files changed, 130 insertions(+), 71 deletions(-) create mode 100644 devU-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts diff --git a/devU-api/package.json b/devU-api/package.json index e908de15..9fbe875d 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 cdb1b7a4..6ed62dfb 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 3ab6c5a7..2c2e6698 100644 --- a/devU-api/src/entities/course/course.model.ts +++ b/devU-api/src/entities/course/course.model.ts @@ -58,4 +58,7 @@ export default class CourseModel { @DeleteDateColumn({ name: 'deleted_at' }) deletedAt?: Date + + @Column({ type: 'boolean', name: 'is_public', default: false }) + isPublic: boolean; } diff --git a/devU-api/src/entities/course/course.serializer.ts b/devU-api/src/entities/course/course.serializer.ts index 8462cffe..2f9e8790 100644 --- a/devU-api/src/entities/course/course.serializer.ts +++ b/devU-api/src/entities/course/course.serializer.ts @@ -12,5 +12,6 @@ export function serialize(course: CourseModel): Course { endDate: course.endDate.toISOString(), createdAt: course.createdAt.toISOString(), updatedAt: course.updatedAt.toISOString(), + isPublic: course.isPublic } } diff --git a/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts b/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts index f761ab3b..bc37d3fd 100644 --- a/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts +++ b/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts @@ -15,6 +15,7 @@ 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, CONSTRAINT "courses_primary_key_constraint" PRIMARY KEY ("id") )` ) diff --git a/devU-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts b/devU-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts new file mode 100644 index 00000000..b5526812 --- /dev/null +++ b/devU-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddAssignmentsAndCourses16267193066081730826999182 implements MigrationInterface { + name = 'AddAssignmentsAndCourses16267193066081730826999182' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "courses" ADD "is_public" boolean NOT NULL DEFAULT false`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "courses" DROP COLUMN "is_public"`); + } + +} diff --git a/devU-client/src/components/listItems/courseListItem.tsx b/devU-client/src/components/listItems/courseListItem.tsx index 368ac2fd..db096d66 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/coursesFormPage.tsx b/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx index e5814ce2..0088d931 100644 --- a/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx +++ b/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx @@ -1,102 +1,121 @@ -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 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 })); // Change to isPublic + }; - 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 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 + }; 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 0e03d98e..ffdf70e9 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; + makePrivateDate?: string; + allowlist?: string[]; + blocklist?: string[]; } From 38853eb4eb41603208e015e5a4cde2ef9bc98d26 Mon Sep 17 00:00:00 2001 From: ashwaqaljanahi2021 Date: Tue, 5 Nov 2024 15:11:57 -0500 Subject: [PATCH 2/2] added public/private checkbox and private date --- devU-api/src/entities/course/course.model.ts | 4 +++ .../src/entities/course/course.serializer.ts | 3 ++- .../1626719306608-addAssignmentsAndCourses.ts | 1 + ...2-addAssignmentsAndCourses1626719306608.ts | 14 ---------- .../pages/forms/courses/courseUpdatePage.tsx | 27 ++++++++++++++++++- .../pages/forms/courses/coursesFormPage.tsx | 16 ++++++++--- devU-shared/src/types/course.types.ts | 2 +- 7 files changed, 47 insertions(+), 20 deletions(-) delete mode 100644 devU-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts diff --git a/devU-api/src/entities/course/course.model.ts b/devU-api/src/entities/course/course.model.ts index 2c2e6698..dd657d2d 100644 --- a/devU-api/src/entities/course/course.model.ts +++ b/devU-api/src/entities/course/course.model.ts @@ -61,4 +61,8 @@ export default class CourseModel { @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 2f9e8790..7094c1ce 100644 --- a/devU-api/src/entities/course/course.serializer.ts +++ b/devU-api/src/entities/course/course.serializer.ts @@ -12,6 +12,7 @@ export function serialize(course: CourseModel): Course { endDate: course.endDate.toISOString(), createdAt: course.createdAt.toISOString(), updatedAt: course.updatedAt.toISOString(), - isPublic: course.isPublic + 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 bc37d3fd..332ac2a8 100644 --- a/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts +++ b/devU-api/src/migration/1626719306608-addAssignmentsAndCourses.ts @@ -16,6 +16,7 @@ export class addAssignmentsAndCourses1626719306608 implements MigrationInterface "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-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts b/devU-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts deleted file mode 100644 index b5526812..00000000 --- a/devU-api/src/migration/1730826999182-addAssignmentsAndCourses1626719306608.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class AddAssignmentsAndCourses16267193066081730826999182 implements MigrationInterface { - name = 'AddAssignmentsAndCourses16267193066081730826999182' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "courses" ADD "is_public" boolean NOT NULL DEFAULT false`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "courses" DROP COLUMN "is_public"`); - } - -} diff --git a/devU-client/src/components/pages/forms/courses/courseUpdatePage.tsx b/devU-client/src/components/pages/forms/courses/courseUpdatePage.tsx index 065df760..5b5ff338 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) @@ -267,6 +278,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 0088d931..ca101c8b 100644 --- a/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx +++ b/devU-client/src/components/pages/forms/courses/coursesFormPage.tsx @@ -20,6 +20,7 @@ const EditCourseFormPage = () => { 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; @@ -27,7 +28,7 @@ const EditCourseFormPage = () => { }; const handleCheckboxChange = (e: React.ChangeEvent) => { - setFormData(prevState => ({ ...prevState, isPublic: e.target.checked })); // Change to isPublic + setFormData(prevState => ({ ...prevState, isPublic: e.target.checked })); }; const handleStartDateChange = (event: React.ChangeEvent) => { @@ -38,6 +39,10 @@ const EditCourseFormPage = () => { setEndDate(event.target.value); }; + const handlePrivateDateChange = (event: React.ChangeEvent) => { + setPrivateDate(event.target.value); + }; + const formatDateForSubmission = (date: string) => { return new Date(date).toISOString(); }; @@ -53,7 +58,8 @@ const EditCourseFormPage = () => { semester: formData.semester, startDate: formatDateForSubmission(startDate), endDate: formatDateForSubmission(endDate), - isPublic: formData.isPublic + isPublic: formData.isPublic, + privateDate: formatDateForSubmission(privateDate) }; RequestService.post('/api/courses/instructor', finalFormData) @@ -98,12 +104,16 @@ const EditCourseFormPage = () => {
+
+ + +