├── .vscode
└── settings.json
├── Project Report
├── index.aux
├── index.fdb_latexmk
├── index.fls
├── index.log
├── index.out
├── index.pdf
├── index.synctex.gz
├── index.tex
└── index.toc
├── README.MD
├── assets
├── logo
│ ├── logo.png
│ └── paper.png
└── ss
│ ├── api-call.png
│ ├── api-call2.png
│ ├── backend.png
│ ├── diagram
│ ├── api.png
│ ├── dataflow-student.png
│ ├── dataflow-teacher.png
│ ├── entity.png
│ ├── level0.png
│ ├── level1.png
│ └── mvc.png
│ ├── exam-running.png
│ ├── frontend-components.png
│ ├── home.png
│ ├── live-exam.png
│ ├── login
│ ├── login-error1.png
│ ├── login-error2.png
│ └── login.png
│ ├── model.png
│ ├── routes.png
│ ├── signin.png
│ ├── signup.png
│ ├── signup
│ ├── department.png
│ ├── designation.png
│ ├── roles.png
│ ├── signup-error-e.png
│ ├── signup-error-u.png
│ ├── signup-teacher.png
│ ├── signup.png
│ └── university.png
│ ├── studnt
│ ├── chnage-info.png
│ ├── course-create-notification-realtime.png
│ ├── course-exams.png
│ ├── courses.png
│ ├── live-exam-cq.png
│ ├── live-exam-mcq.png
│ ├── notifications.png
│ ├── previos-exam.png
│ ├── previous cq.png
│ ├── previous-exam-cq.png
│ ├── previous-exam-non-participate.png
│ ├── previous-exams.png
│ ├── report-question.png
│ ├── tab-chnage-alert.png
│ ├── upcoming-exam-section.png
│ ├── upcoming-exam.png
│ └── window chnage notification.png
│ ├── teacher
│ ├── all-exams.png
│ ├── course-create.png
│ ├── courses-create.png
│ ├── cq-create.png
│ ├── cq-examine.png
│ ├── cqexam-previous.png
│ ├── exam-create.png
│ ├── examine-cq2.png
│ ├── marksheet.png
│ ├── mcq-create.png
│ ├── revious-exam.png
│ └── set-exam.png
│ └── upcoming-exam-countdown.png
├── client
├── .eslintcache
├── .gitignore
├── README.MD
├── package-lock.json
├── package.json
├── public
│ ├── index.html
│ ├── manifest.json
│ ├── robots.txt
│ └── static
│ │ ├── favicon.ico
│ │ └── paper.png
└── src
│ ├── Components
│ ├── 404
│ │ ├── Error404.js
│ │ └── style.css
│ ├── Authentication
│ │ ├── SignIn.css
│ │ ├── SignIn.js
│ │ └── SignUp.js
│ ├── Course
│ │ ├── Course.js
│ │ ├── Course.scss
│ │ ├── CreateExam
│ │ │ ├── CreateExam.js
│ │ │ ├── CreateExam.scss
│ │ │ ├── ExamType.js
│ │ │ └── Question.js
│ │ ├── Exams.js
│ │ ├── Info.js
│ │ ├── Sidebar.js
│ │ ├── Sidebar.scss
│ │ ├── Students.js
│ │ └── Teacher.js
│ ├── Exam
│ │ └── Exam.js
│ ├── Generic
│ │ ├── Forms.js
│ │ ├── Forms.scss
│ │ ├── Loader.js
│ │ └── Notification.js
│ ├── Home
│ │ ├── Home.js
│ │ └── Home.scss
│ ├── LandingPage
│ │ ├── LandingPage.js
│ │ ├── LandingPage.scss
│ │ └── pic.jpg
│ ├── Layout
│ │ └── Layout.js
│ ├── LiveExam
│ │ ├── LiveExam.js
│ │ ├── LiveExam.scss
│ │ ├── Loading.js
│ │ ├── Result.js
│ │ └── ResultLoading.js
│ ├── Navbar
│ │ └── Navbar.js
│ ├── Notifications
│ │ └── Notification.js
│ ├── PreviousExam
│ │ ├── ExamInfo.js
│ │ ├── Examine.js
│ │ ├── MarkSheet.js
│ │ ├── PreviousExam.css
│ │ └── PreviousExam.js
│ ├── Profile
│ │ ├── Profile.js
│ │ └── Profile.scss
│ ├── Timer
│ │ ├── Timer.css
│ │ └── Timer.js
│ └── UpcomingExam
│ │ └── UpcomingExam.js
│ ├── Containers
│ ├── App.css
│ ├── App.js
│ └── App.test.js
│ ├── hoc
│ └── Auxilary.js
│ ├── index.css
│ ├── index.js
│ ├── reportWebVitals.js
│ └── setupTests.js
├── database
├── courses
├── cqexams
├── cqquestions
├── mcqexams
├── mcqquestions
├── students
├── teachers
└── universities
├── package-lock.json
└── server
├── .env
├── .gitignore
├── README.MD
├── app.js
├── controllers
├── auth.js
├── error.js
├── exam.js
├── notification.js
├── student.js
├── teacher.js
└── university.js
├── data
└── data.js
├── middleware
├── apiResponseInJson.js
├── authenticateJWS.js
├── errorHandler.js
└── restrictUser.js
├── models
├── course.js
├── cqExam.js
├── cqExamine.js
├── cqQuestion.js
├── mcqExam.js
├── mcqQuestion.js
├── notification.js
├── onCqExam.js
├── onMcqExam.js
├── student.js
├── teacher.js
└── university.js
├── package-lock.json
├── package.json
├── routes
├── authoRoutes.js
├── index.js
├── studentRoutes.js
├── teacherRoutes.js
└── univesityRoutes.js
├── server.js
└── utils
├── apiCallError.js
├── catchAsync.js
└── validator.js
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.ignoreWords": [
3 | "signup"
4 | ]
5 | }
--------------------------------------------------------------------------------
/Project Report/index.out:
--------------------------------------------------------------------------------
1 | \BOOKMARK [1][-]{section.1}{Project Introduction}{}% 1
2 | \BOOKMARK [1][-]{section.2}{Project Background}{}% 2
3 | \BOOKMARK [1][-]{section.3}{Project Description}{}% 3
4 | \BOOKMARK [2][-]{subsection.3.1}{Teacher}{section.3}% 4
5 | \BOOKMARK [3][-]{subsubsection.3.1.1}{Course Create}{subsection.3.1}% 5
6 | \BOOKMARK [3][-]{subsubsection.3.1.2}{Question Create}{subsection.3.1}% 6
7 | \BOOKMARK [3][-]{subsubsection.3.1.3}{Exam Create}{subsection.3.1}% 7
8 | \BOOKMARK [3][-]{subsubsection.3.1.4}{CQ Examine}{subsection.3.1}% 8
9 | \BOOKMARK [3][-]{subsubsection.3.1.5}{Marksheet Check}{subsection.3.1}% 9
10 | \BOOKMARK [3][-]{subsubsection.3.1.6}{Feedback Check}{subsection.3.1}% 10
11 | \BOOKMARK [3][-]{subsubsection.3.1.7}{Result Print}{subsection.3.1}% 11
12 | \BOOKMARK [2][-]{subsection.3.2}{Student}{section.3}% 12
13 | \BOOKMARK [3][-]{subsubsection.3.2.1}{Real-Time Exam}{subsection.3.2}% 13
14 | \BOOKMARK [3][-]{subsubsection.3.2.2}{Revise Previous Exam}{subsection.3.2}% 14
15 | \BOOKMARK [3][-]{subsubsection.3.2.3}{Realtime Notifications}{subsection.3.2}% 15
16 | \BOOKMARK [3][-]{subsubsection.3.2.4}{Feedback}{subsection.3.2}% 16
17 | \BOOKMARK [3][-]{subsubsection.3.2.5}{Late Participate}{subsection.3.2}% 17
18 | \BOOKMARK [2][-]{subsection.3.3}{Exam}{section.3}% 18
19 | \BOOKMARK [3][-]{subsubsection.3.3.1}{Question features}{subsection.3.3}% 19
20 | \BOOKMARK [3][-]{subsubsection.3.3.2}{Exam Features}{subsection.3.3}% 20
21 | \BOOKMARK [1][-]{section.4}{User Interface Specifications}{}% 21
22 | \BOOKMARK [2][-]{subsection.4.1}{Authentication}{section.4}% 22
23 | \BOOKMARK [3][-]{subsubsection.4.1.1}{Signup}{subsection.4.1}% 23
24 | \BOOKMARK [3][-]{subsubsection.4.1.2}{Login}{subsection.4.1}% 24
25 | \BOOKMARK [2][-]{subsection.4.2}{Home Page}{section.4}% 25
26 | \BOOKMARK [3][-]{subsubsection.4.2.1}{Courses}{subsection.4.2}% 26
27 | \BOOKMARK [3][-]{subsubsection.4.2.2}{Course Creation}{subsection.4.2}% 27
28 | \BOOKMARK [3][-]{subsubsection.4.2.3}{Countdown Timer}{subsection.4.2}% 28
29 | \BOOKMARK [3][-]{subsubsection.4.2.4}{Upcoming Exams}{subsection.4.2}% 29
30 | \BOOKMARK [3][-]{subsubsection.4.2.5}{Previous Exams}{subsection.4.2}% 30
31 | \BOOKMARK [2][-]{subsection.4.3}{Upcoming Exam Page}{section.4}% 31
32 | \BOOKMARK [2][-]{subsection.4.4}{Previous Exam Page}{section.4}% 32
33 | \BOOKMARK [3][-]{subsubsection.4.4.1}{Exam Detail}{subsection.4.4}% 33
34 | \BOOKMARK [3][-]{subsubsection.4.4.2}{My Answers}{subsection.4.4}% 34
35 | \BOOKMARK [3][-]{subsubsection.4.4.3}{Marksheet}{subsection.4.4}% 35
36 | \BOOKMARK [3][-]{subsubsection.4.4.4}{Reports}{subsection.4.4}% 36
37 | \BOOKMARK [2][-]{subsection.4.5}{Course Page}{section.4}% 37
38 | \BOOKMARK [3][-]{subsubsection.4.5.1}{Course Info}{subsection.4.5}% 38
39 | \BOOKMARK [3][-]{subsubsection.4.5.2}{Exam Creation}{subsection.4.5}% 39
40 | \BOOKMARK [3][-]{subsubsection.4.5.3}{All Exams}{subsection.4.5}% 40
41 | \BOOKMARK [3][-]{subsubsection.4.5.4}{Students}{subsection.4.5}% 41
42 | \BOOKMARK [3][-]{subsubsection.4.5.5}{Teacher Info}{subsection.4.5}% 42
43 | \BOOKMARK [2][-]{subsection.4.6}{Real-time Exam}{section.4}% 43
44 | \BOOKMARK [2][-]{subsection.4.7}{Examine CQ}{section.4}% 44
45 | \BOOKMARK [2][-]{subsection.4.8}{Notifications}{section.4}% 45
46 | \BOOKMARK [1][-]{section.5}{System Design}{}% 46
47 | \BOOKMARK [2][-]{subsection.5.1}{Use Case Diagram}{section.5}% 47
48 | \BOOKMARK [2][-]{subsection.5.2}{Context Diagram}{section.5}% 48
49 | \BOOKMARK [2][-]{subsection.5.3}{Data Flow Diagram}{section.5}% 49
50 | \BOOKMARK [2][-]{subsection.5.4}{Entity Relationship Diagram}{section.5}% 50
51 | \BOOKMARK [1][-]{section.6}{System Architecture}{}% 51
52 | \BOOKMARK [2][-]{subsection.6.1}{Front-End}{section.6}% 52
53 | \BOOKMARK [2][-]{subsection.6.2}{Back-end}{section.6}% 53
54 | \BOOKMARK [1][-]{section.7}{System Implementation}{}% 54
55 | \BOOKMARK [2][-]{subsection.7.1}{Authentication}{section.7}% 55
56 | \BOOKMARK [2][-]{subsection.7.2}{Pattern Of Code}{section.7}% 56
57 | \BOOKMARK [3][-]{subsubsection.7.2.1}{Frontend}{subsection.7.2}% 57
58 | \BOOKMARK [3][-]{subsubsection.7.2.2}{Backend}{subsection.7.2}% 58
59 | \BOOKMARK [1][-]{section.8}{Testing And validation}{}% 59
60 | \BOOKMARK [2][-]{subsection.8.1}{Functional Testing}{section.8}% 60
61 | \BOOKMARK [3][-]{subsubsection.8.1.1}{Unit Testing : }{subsection.8.1}% 61
62 | \BOOKMARK [3][-]{subsubsection.8.1.2}{Integration testing : }{subsection.8.1}% 62
63 | \BOOKMARK [3][-]{subsubsection.8.1.3}{System testing: }{subsection.8.1}% 63
64 | \BOOKMARK [3][-]{subsubsection.8.1.4}{Acceptance Testing : }{subsection.8.1}% 64
65 | \BOOKMARK [2][-]{subsection.8.2}{Non-Functional Testing}{section.8}% 65
66 | \BOOKMARK [3][-]{subsubsection.8.2.1}{Load Testing}{subsection.8.2}% 66
67 | \BOOKMARK [3][-]{subsubsection.8.2.2}{Security Testing}{subsection.8.2}% 67
68 | \BOOKMARK [3][-]{subsubsection.8.2.3}{Reliability Testing}{subsection.8.2}% 68
69 | \BOOKMARK [3][-]{subsubsection.8.2.4}{Efficiency Testing}{subsection.8.2}% 69
70 | \BOOKMARK [1][-]{section.9}{Future Enhancement}{}% 70
71 | \BOOKMARK [2][-]{subsection.9.1}{Combined Exams}{section.9}% 71
72 | \BOOKMARK [2][-]{subsection.9.2}{Lab Exams}{section.9}% 72
73 | \BOOKMARK [2][-]{subsection.9.3}{Realtime Chat}{section.9}% 73
74 | \BOOKMARK [2][-]{subsection.9.4}{Mobile Version}{section.9}% 74
75 | \BOOKMARK [1][-]{section.10}{Conclusion}{}% 75
76 | \BOOKMARK [1][-]{section.11}{References}{}% 76
77 |
--------------------------------------------------------------------------------
/Project Report/index.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/Project Report/index.pdf
--------------------------------------------------------------------------------
/Project Report/index.synctex.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/Project Report/index.synctex.gz
--------------------------------------------------------------------------------
/Project Report/index.toc:
--------------------------------------------------------------------------------
1 | \contentsline {section}{\numberline {1}Project Introduction}{5}{section.1}%
2 | \contentsline {section}{\numberline {2}Project Background}{5}{section.2}%
3 | \contentsline {section}{\numberline {3}Project Description}{5}{section.3}%
4 | \contentsline {subsection}{\numberline {3.1}Teacher}{6}{subsection.3.1}%
5 | \contentsline {subsubsection}{\numberline {3.1.1}Course Create}{6}{subsubsection.3.1.1}%
6 | \contentsline {subsubsection}{\numberline {3.1.2}Question Create}{6}{subsubsection.3.1.2}%
7 | \contentsline {subsubsection}{\numberline {3.1.3}Exam Create}{6}{subsubsection.3.1.3}%
8 | \contentsline {subsubsection}{\numberline {3.1.4}CQ Examine}{6}{subsubsection.3.1.4}%
9 | \contentsline {subsubsection}{\numberline {3.1.5}Marksheet Check}{6}{subsubsection.3.1.5}%
10 | \contentsline {subsubsection}{\numberline {3.1.6}Feedback Check}{6}{subsubsection.3.1.6}%
11 | \contentsline {subsubsection}{\numberline {3.1.7}Result Print}{6}{subsubsection.3.1.7}%
12 | \contentsline {subsection}{\numberline {3.2}Student}{7}{subsection.3.2}%
13 | \contentsline {subsubsection}{\numberline {3.2.1}Real-Time Exam}{7}{subsubsection.3.2.1}%
14 | \contentsline {subsubsection}{\numberline {3.2.2}Revise Previous Exam}{7}{subsubsection.3.2.2}%
15 | \contentsline {subsubsection}{\numberline {3.2.3}Realtime Notifications}{7}{subsubsection.3.2.3}%
16 | \contentsline {subsubsection}{\numberline {3.2.4}Feedback}{7}{subsubsection.3.2.4}%
17 | \contentsline {subsubsection}{\numberline {3.2.5}Late Participate}{7}{subsubsection.3.2.5}%
18 | \contentsline {subsection}{\numberline {3.3}Exam}{7}{subsection.3.3}%
19 | \contentsline {subsubsection}{\numberline {3.3.1}Question features}{8}{subsubsection.3.3.1}%
20 | \contentsline {subsubsection}{\numberline {3.3.2}Exam Features}{8}{subsubsection.3.3.2}%
21 | \contentsline {section}{\numberline {4}User Interface Specifications}{8}{section.4}%
22 | \contentsline {subsection}{\numberline {4.1}Authentication}{8}{subsection.4.1}%
23 | \contentsline {subsubsection}{\numberline {4.1.1}Signup}{8}{subsubsection.4.1.1}%
24 | \contentsline {subsubsection}{\numberline {4.1.2}Login}{11}{subsubsection.4.1.2}%
25 | \contentsline {subsection}{\numberline {4.2}Home Page}{13}{subsection.4.2}%
26 | \contentsline {subsubsection}{\numberline {4.2.1}Courses}{13}{subsubsection.4.2.1}%
27 | \contentsline {subsubsection}{\numberline {4.2.2}Course Creation}{13}{subsubsection.4.2.2}%
28 | \contentsline {subsubsection}{\numberline {4.2.3}Countdown Timer}{14}{subsubsection.4.2.3}%
29 | \contentsline {subsubsection}{\numberline {4.2.4}Upcoming Exams}{14}{subsubsection.4.2.4}%
30 | \contentsline {subsubsection}{\numberline {4.2.5}Previous Exams}{14}{subsubsection.4.2.5}%
31 | \contentsline {subsection}{\numberline {4.3}Upcoming Exam Page}{14}{subsection.4.3}%
32 | \contentsline {subsection}{\numberline {4.4}Previous Exam Page}{15}{subsection.4.4}%
33 | \contentsline {subsubsection}{\numberline {4.4.1}Exam Detail}{15}{subsubsection.4.4.1}%
34 | \contentsline {subsubsection}{\numberline {4.4.2}My Answers}{16}{subsubsection.4.4.2}%
35 | \contentsline {subsubsection}{\numberline {4.4.3}Marksheet}{17}{subsubsection.4.4.3}%
36 | \contentsline {subsubsection}{\numberline {4.4.4}Reports}{17}{subsubsection.4.4.4}%
37 | \contentsline {subsection}{\numberline {4.5}Course Page}{17}{subsection.4.5}%
38 | \contentsline {subsubsection}{\numberline {4.5.1}Course Info}{17}{subsubsection.4.5.1}%
39 | \contentsline {subsubsection}{\numberline {4.5.2}Exam Creation}{17}{subsubsection.4.5.2}%
40 | \contentsline {subsubsection}{\numberline {4.5.3}All Exams}{20}{subsubsection.4.5.3}%
41 | \contentsline {subsubsection}{\numberline {4.5.4}Students}{20}{subsubsection.4.5.4}%
42 | \contentsline {subsubsection}{\numberline {4.5.5}Teacher Info}{20}{subsubsection.4.5.5}%
43 | \contentsline {subsection}{\numberline {4.6}Real-time Exam}{20}{subsection.4.6}%
44 | \contentsline {subsection}{\numberline {4.7}Examine CQ}{21}{subsection.4.7}%
45 | \contentsline {subsection}{\numberline {4.8}Notifications}{21}{subsection.4.8}%
46 | \contentsline {section}{\numberline {5}System Design}{23}{section.5}%
47 | \contentsline {subsection}{\numberline {5.1}Use Case Diagram}{23}{subsection.5.1}%
48 | \contentsline {subsection}{\numberline {5.2}Context Diagram}{24}{subsection.5.2}%
49 | \contentsline {subsection}{\numberline {5.3}Data Flow Diagram}{24}{subsection.5.3}%
50 | \contentsline {subsection}{\numberline {5.4}Entity Relationship Diagram}{26}{subsection.5.4}%
51 | \contentsline {section}{\numberline {6}System Architecture}{27}{section.6}%
52 | \contentsline {subsection}{\numberline {6.1}Front-End}{27}{subsection.6.1}%
53 | \contentsline {subsection}{\numberline {6.2}Back-end}{27}{subsection.6.2}%
54 | \contentsline {section}{\numberline {7}System Implementation}{27}{section.7}%
55 | \contentsline {subsection}{\numberline {7.1}Authentication}{28}{subsection.7.1}%
56 | \contentsline {subsection}{\numberline {7.2}Pattern Of Code}{28}{subsection.7.2}%
57 | \contentsline {subsubsection}{\numberline {7.2.1}Frontend}{28}{subsubsection.7.2.1}%
58 | \contentsline {subsubsection}{\numberline {7.2.2}Backend}{30}{subsubsection.7.2.2}%
59 | \contentsline {section}{\numberline {8}Testing And validation}{32}{section.8}%
60 | \contentsline {subsection}{\numberline {8.1}Functional Testing}{32}{subsection.8.1}%
61 | \contentsline {subsubsection}{\numberline {8.1.1}Unit Testing : }{32}{subsubsection.8.1.1}%
62 | \contentsline {subsubsection}{\numberline {8.1.2}Integration testing : }{32}{subsubsection.8.1.2}%
63 | \contentsline {subsubsection}{\numberline {8.1.3}System testing: }{32}{subsubsection.8.1.3}%
64 | \contentsline {subsubsection}{\numberline {8.1.4}Acceptance Testing : }{33}{subsubsection.8.1.4}%
65 | \contentsline {subsection}{\numberline {8.2}Non-Functional Testing}{33}{subsection.8.2}%
66 | \contentsline {subsubsection}{\numberline {8.2.1}Load Testing}{33}{subsubsection.8.2.1}%
67 | \contentsline {subsubsection}{\numberline {8.2.2}Security Testing}{33}{subsubsection.8.2.2}%
68 | \contentsline {subsubsection}{\numberline {8.2.3}Reliability Testing}{33}{subsubsection.8.2.3}%
69 | \contentsline {subsubsection}{\numberline {8.2.4}Efficiency Testing}{33}{subsubsection.8.2.4}%
70 | \contentsline {section}{\numberline {9}Future Enhancement}{34}{section.9}%
71 | \contentsline {subsection}{\numberline {9.1}Combined Exams}{34}{subsection.9.1}%
72 | \contentsline {subsection}{\numberline {9.2}Lab Exams}{34}{subsection.9.2}%
73 | \contentsline {subsection}{\numberline {9.3}Realtime Chat}{34}{subsection.9.3}%
74 | \contentsline {subsection}{\numberline {9.4}Mobile Version}{34}{subsection.9.4}%
75 | \contentsline {section}{\numberline {10}Conclusion}{34}{section.10}%
76 | \contentsline {section}{\numberline {11}References}{34}{section.11}%
77 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Paper (An Online Exam Management System)
4 |
5 |
6 | Table
7 |
8 | - [Contents :](#table-)
9 | - [Introduction](#introduction)
10 | - [Description](#description)
11 | - [Roles](#roles)
12 | - [Features](#features)
13 | - [Exam Features](#exam-features)
14 | - [Teacher's Features](#teachers-features)
15 | - [Student's Features](#students-features)
16 | - [Technogogies](#technogogies)
17 | - [Source Code](#source-code)
18 | - [Whole Project SS](#whole-project-ss)
19 | - [About Developers](#about-developers)
20 |
21 |
22 | # Contents
23 |
24 | ## Introduction
25 |
26 | This is a web based application to manage online examinations.
27 |
28 | ## Description
29 |
30 | Our web based online exam management system is capable of arranging exams and taking tests. We mainly focus on taking CQ and MCQ exams arrranged by Teachers.
31 |
32 | ### Roles
33 |
34 | There are two types of roles :
35 |
36 | 1. Student
37 | 2. Teacher
38 |
39 | ### Features
40 |
41 | Our main features are
42 |
43 | #### Exam Features
44 |
45 | - Both CQ and MCQ exams
46 | 
47 | - Setting time and date for exams
48 | 
49 | - Setting time for per cq and mcq questions
50 |
51 | - MCQ
52 | 
53 | - CQ
54 | 
55 |
56 | - Realtime exam
57 |
58 | - MCQ
59 | 
60 | - CQ
61 | 
62 |
63 | - Feedback options for each questions
64 | 
65 | - Alert notifications for changing windows or tabs on exam time (this counts will be shown to the teacher)
66 | 
67 | - Disable question copy/cut
68 | - Disbale copy/paste on answer textfield
69 |
70 | #### Teacher's Features
71 |
72 | - Course Create
73 | 
74 | - able to set exams for specific date and time
75 | - Checking marksheet after exam
76 | 
77 | - Checking and marking CQ exams
78 | 
79 |
80 | #### Student's Features
81 |
82 | - Realtime notifications of -
83 | - Course creation
84 | 
85 | - exam creation
86 | - CQ result publication
87 | - All Notifications :
88 | - 
89 | - Upcoming Exam countdown on homepage
90 | 
91 | 
92 | - Able to check their paper later
93 |
94 | - MCQ :
95 |
96 | - Participated :
97 | 
98 | - Not participated :
99 | 
100 |
101 | - CQ :
102 | 
103 |
104 | - Report per question if anything goes wrong
105 |
106 | ## Technogogies
107 |
108 | - Frontend
109 |
110 | - Framework
111 |
112 | - React Js
113 |
114 | - UI Design
115 |
116 | - React Bootstrap
117 | - Material UI
118 |
119 | - Backend
120 |
121 | - Framework
122 |
123 | - ExpressJs
124 |
125 | - API
126 | - RESTFull API
127 |
128 | - Database
129 |
130 | - MongoDB
131 |
132 | - Realtime Integration
133 | - SocketIO
134 |
135 | ## Source Code
136 |
137 | - [Client](client/)
138 |
139 | - Server
140 | - [API](server/)
141 |
142 | ## Whole Project SS
143 |
144 | 
145 | 
146 | 
147 | 
148 | 
149 | 
150 | 
151 |
152 | ## About Developers
153 |
154 | - [Sania Sayeda Rahman](https://github.com/sania51)
155 | - [Mehedi Hasan Shifat](https://github.com/jspw)
156 |
--------------------------------------------------------------------------------
/assets/logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/logo/logo.png
--------------------------------------------------------------------------------
/assets/logo/paper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/logo/paper.png
--------------------------------------------------------------------------------
/assets/ss/api-call.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/api-call.png
--------------------------------------------------------------------------------
/assets/ss/api-call2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/api-call2.png
--------------------------------------------------------------------------------
/assets/ss/backend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/backend.png
--------------------------------------------------------------------------------
/assets/ss/diagram/api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/diagram/api.png
--------------------------------------------------------------------------------
/assets/ss/diagram/dataflow-student.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/diagram/dataflow-student.png
--------------------------------------------------------------------------------
/assets/ss/diagram/dataflow-teacher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/diagram/dataflow-teacher.png
--------------------------------------------------------------------------------
/assets/ss/diagram/entity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/diagram/entity.png
--------------------------------------------------------------------------------
/assets/ss/diagram/level0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/diagram/level0.png
--------------------------------------------------------------------------------
/assets/ss/diagram/level1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/diagram/level1.png
--------------------------------------------------------------------------------
/assets/ss/diagram/mvc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/diagram/mvc.png
--------------------------------------------------------------------------------
/assets/ss/exam-running.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/exam-running.png
--------------------------------------------------------------------------------
/assets/ss/frontend-components.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/frontend-components.png
--------------------------------------------------------------------------------
/assets/ss/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/home.png
--------------------------------------------------------------------------------
/assets/ss/live-exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/live-exam.png
--------------------------------------------------------------------------------
/assets/ss/login/login-error1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/login/login-error1.png
--------------------------------------------------------------------------------
/assets/ss/login/login-error2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/login/login-error2.png
--------------------------------------------------------------------------------
/assets/ss/login/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/login/login.png
--------------------------------------------------------------------------------
/assets/ss/model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/model.png
--------------------------------------------------------------------------------
/assets/ss/routes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/routes.png
--------------------------------------------------------------------------------
/assets/ss/signin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signin.png
--------------------------------------------------------------------------------
/assets/ss/signup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup.png
--------------------------------------------------------------------------------
/assets/ss/signup/department.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/department.png
--------------------------------------------------------------------------------
/assets/ss/signup/designation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/designation.png
--------------------------------------------------------------------------------
/assets/ss/signup/roles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/roles.png
--------------------------------------------------------------------------------
/assets/ss/signup/signup-error-e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/signup-error-e.png
--------------------------------------------------------------------------------
/assets/ss/signup/signup-error-u.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/signup-error-u.png
--------------------------------------------------------------------------------
/assets/ss/signup/signup-teacher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/signup-teacher.png
--------------------------------------------------------------------------------
/assets/ss/signup/signup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/signup.png
--------------------------------------------------------------------------------
/assets/ss/signup/university.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/signup/university.png
--------------------------------------------------------------------------------
/assets/ss/studnt/chnage-info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/chnage-info.png
--------------------------------------------------------------------------------
/assets/ss/studnt/course-create-notification-realtime.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/course-create-notification-realtime.png
--------------------------------------------------------------------------------
/assets/ss/studnt/course-exams.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/course-exams.png
--------------------------------------------------------------------------------
/assets/ss/studnt/courses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/courses.png
--------------------------------------------------------------------------------
/assets/ss/studnt/live-exam-cq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/live-exam-cq.png
--------------------------------------------------------------------------------
/assets/ss/studnt/live-exam-mcq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/live-exam-mcq.png
--------------------------------------------------------------------------------
/assets/ss/studnt/notifications.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/notifications.png
--------------------------------------------------------------------------------
/assets/ss/studnt/previos-exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/previos-exam.png
--------------------------------------------------------------------------------
/assets/ss/studnt/previous cq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/previous cq.png
--------------------------------------------------------------------------------
/assets/ss/studnt/previous-exam-cq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/previous-exam-cq.png
--------------------------------------------------------------------------------
/assets/ss/studnt/previous-exam-non-participate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/previous-exam-non-participate.png
--------------------------------------------------------------------------------
/assets/ss/studnt/previous-exams.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/previous-exams.png
--------------------------------------------------------------------------------
/assets/ss/studnt/report-question.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/report-question.png
--------------------------------------------------------------------------------
/assets/ss/studnt/tab-chnage-alert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/tab-chnage-alert.png
--------------------------------------------------------------------------------
/assets/ss/studnt/upcoming-exam-section.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/upcoming-exam-section.png
--------------------------------------------------------------------------------
/assets/ss/studnt/upcoming-exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/upcoming-exam.png
--------------------------------------------------------------------------------
/assets/ss/studnt/window chnage notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/studnt/window chnage notification.png
--------------------------------------------------------------------------------
/assets/ss/teacher/all-exams.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/all-exams.png
--------------------------------------------------------------------------------
/assets/ss/teacher/course-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/course-create.png
--------------------------------------------------------------------------------
/assets/ss/teacher/courses-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/courses-create.png
--------------------------------------------------------------------------------
/assets/ss/teacher/cq-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/cq-create.png
--------------------------------------------------------------------------------
/assets/ss/teacher/cq-examine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/cq-examine.png
--------------------------------------------------------------------------------
/assets/ss/teacher/cqexam-previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/cqexam-previous.png
--------------------------------------------------------------------------------
/assets/ss/teacher/exam-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/exam-create.png
--------------------------------------------------------------------------------
/assets/ss/teacher/examine-cq2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/examine-cq2.png
--------------------------------------------------------------------------------
/assets/ss/teacher/marksheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/marksheet.png
--------------------------------------------------------------------------------
/assets/ss/teacher/mcq-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/mcq-create.png
--------------------------------------------------------------------------------
/assets/ss/teacher/revious-exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/revious-exam.png
--------------------------------------------------------------------------------
/assets/ss/teacher/set-exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/teacher/set-exam.png
--------------------------------------------------------------------------------
/assets/ss/upcoming-exam-countdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/assets/ss/upcoming-exam-countdown.png
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/client/README.MD:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
13 |
14 | The page will reload if you make edits.\
15 | You will also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
35 |
36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
39 |
40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
48 | ### Code Splitting
49 |
50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
51 |
52 | ### Analyzing the Bundle Size
53 |
54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
55 |
56 | ### Making a Progressive Web App
57 |
58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
59 |
60 | ### Advanced Configuration
61 |
62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
63 |
64 | ### Deployment
65 |
66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
67 |
68 | ### `npm run build` fails to minify
69 |
70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
71 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.11.2",
7 | "@material-ui/data-grid": "^4.0.0-alpha.19",
8 | "@material-ui/icons": "^4.11.2",
9 | "@material-ui/lab": "^4.0.0-alpha.57",
10 | "@testing-library/jest-dom": "^5.11.8",
11 | "@testing-library/react": "^11.2.3",
12 | "@testing-library/user-event": "^12.6.0",
13 | "antd": "^4.12.2",
14 | "axios": "^0.21.1",
15 | "bootstrap": "^4.6.0",
16 | "final-form": "^4.20.1",
17 | "jspdf": "^2.3.0",
18 | "node-sass": "^4.14.1",
19 | "react": "^17.0.1",
20 | "react-bootstrap": "^1.4.3",
21 | "react-dom": "^17.0.1",
22 | "react-final-form": "^6.5.2",
23 | "react-icons": "^4.1.0",
24 | "react-router-dom": "^5.2.0",
25 | "react-scripts": "4.0.1",
26 | "reactstrap": "^8.9.0",
27 | "socket.io-client": "^3.1.0",
28 | "web-vitals": "^0.2.4"
29 | },
30 | "scripts": {
31 | "start": "react-scripts start",
32 | "build": "react-scripts build",
33 | "test": "react-scripts test",
34 | "eject": "react-scripts eject"
35 | },
36 | "eslintConfig": {
37 | "extends": [
38 | "react-app",
39 | "react-app/jest"
40 | ]
41 | },
42 | "proxy": "http://localhost:8080",
43 | "browserslist": {
44 | "production": [
45 | ">0.2%",
46 | "not dead",
47 | "not op_mini all"
48 | ],
49 | "development": [
50 | "last 1 chrome version",
51 | "last 1 firefox version",
52 | "last 1 safari version"
53 | ]
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 | Paper
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client/public/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/client/public/static/favicon.ico
--------------------------------------------------------------------------------
/client/public/static/paper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/client/public/static/paper.png
--------------------------------------------------------------------------------
/client/src/Components/404/Error404.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import MuiAlert from "@material-ui/lab/Alert";
3 | import './style.css'
4 | import { Container } from "react-bootstrap";
5 | import { makeStyles } from "@material-ui/core/styles";
6 |
7 | const useStyles = makeStyles((theme) => ({
8 | root: {
9 | width: "100%",
10 | "& > * + *": {
11 | marginTop: theme.spacing(2),
12 | },
13 | },
14 | }));
15 |
16 | function Alert(props) {
17 | return ;
18 | }
19 |
20 | const Error404 = () => {
21 | const classes = useStyles();
22 | return (
23 | <>
24 |
25 |
26 |
404 Page Not Found!
27 |
28 |
29 | >
30 | );
31 | };
32 |
33 | export default Error404;
34 |
--------------------------------------------------------------------------------
/client/src/Components/404/style.css:
--------------------------------------------------------------------------------
1 | .center {
2 | margin: auto;
3 | /* width: 50%; */
4 | /* border: 3px solid green; */
5 | padding:20%;
6 | }
--------------------------------------------------------------------------------
/client/src/Components/Authentication/SignIn.css:
--------------------------------------------------------------------------------
1 | .sign {
2 | /* width: 50%;
3 | margin: 0 auto; */
4 | display: flex;
5 | justify-content: center;
6 | }
7 | .errorMsg {
8 | background-color: rgb(250, 214, 214);
9 | margin: 20px;
10 | padding: 7px 10px;
11 | border: 2px solid rgb(255, 197, 197);
12 | border-radius: 5px;
13 | color: rgb(211, 12, 12);
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/Components/Authentication/SignIn.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Container, Button } from "@material-ui/core";
3 | import { makeStyles } from "@material-ui/core/styles";
4 | import Forms from "../Generic/Forms";
5 | import Grid from "@material-ui/core/Grid";
6 | import MuiAlert from "@material-ui/lab/Alert";
7 | import { Link } from "react-router-dom";
8 | import Typography from "@material-ui/core/Typography";
9 | import { useHistory } from "react-router-dom";
10 | import "./SignIn.css";
11 |
12 | const apiDomain = "http://localhost:8080/";
13 |
14 | const useStyles = makeStyles((theme) => ({
15 | textField: {
16 | marginTop: theme.spacing(2),
17 | },
18 | root: {
19 | display: "flex",
20 | flexWrap: "wrap",
21 | width: "100%",
22 | "& > * + *": {
23 | marginTop: theme.spacing(2),
24 | },
25 | },
26 | }));
27 |
28 | function Alert(props) {
29 | return ;
30 | }
31 |
32 | export default function SignUp() {
33 | const classes = useStyles();
34 |
35 | let history = useHistory();
36 |
37 | const [values, setValues] = useState({
38 | email: "",
39 | password: "",
40 | error: "",
41 | });
42 |
43 | const obj = {
44 | email: values.email,
45 | password: values.password,
46 | };
47 |
48 | const body = JSON.stringify(obj);
49 |
50 | const handleSignIn = (e) => {
51 | fetchData();
52 | e.preventDefault();
53 | };
54 | const fetchData = async () => {
55 | const endpoint = "auth/login";
56 | const requestOptions = {
57 | method: "POST",
58 | headers: { "Content-Type": "application/json" },
59 | body: body,
60 | };
61 | const response = await fetch(`${apiDomain}${endpoint}`, requestOptions);
62 | const data = await response.json();
63 |
64 | console.log(data);
65 |
66 | if (data.status === "OK") {
67 | // const userdata = {
68 | // token: data.result.jwt.token,
69 | // role: data.result.data.role.toLowerCase(),
70 | // id: data.result.data.id,
71 | // };
72 | localStorage.setItem("data", JSON.stringify(data.result.data));
73 | history.push("/");
74 | window.location.reload();
75 |
76 | } else {
77 | setValues({ ...values, error: data.result });
78 | }
79 | };
80 |
81 | const handleChange = (prop) => (event) => {
82 | setValues({ ...values, [prop]: event.target.value });
83 | };
84 | return (
85 |
86 |
92 |
93 |
94 | Welcome Back!!
95 | Please sign into your account
96 |
97 |
98 | {values.error !== "" ? (
99 |
100 |
101 |
102 | {values.error}
103 |
104 |
105 |
106 | ) : null}
107 |
153 |
154 |
155 | );
156 | }
157 |
--------------------------------------------------------------------------------
/client/src/Components/Authentication/SignUp.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Container, Button } from "@material-ui/core";
3 | import { makeStyles } from "@material-ui/core/styles";
4 | import Forms from "../Generic/Forms";
5 | import Grid from "@material-ui/core/Grid";
6 | import MuiAlert from "@material-ui/lab/Alert";
7 | import { Link } from "react-router-dom";
8 | import Typography from "@material-ui/core/Typography";
9 | import { useHistory } from "react-router-dom";
10 | import "./SignIn.css";
11 |
12 | const apiDomain = "http://localhost:8080/";
13 |
14 | const useStyles = makeStyles((theme) => ({
15 | root: {
16 | display: "flex",
17 | flexWrap: "wrap",
18 | },
19 | margin: {
20 | // margin: theme.spacing(1),
21 | },
22 | textField: {
23 | // width: "15vw",
24 | // margin: theme.spacing(1),
25 | paddingRight: theme.spacing(1),
26 | marginTop: theme.spacing(2),
27 | },
28 | root: {
29 | width: "100%",
30 | "& > * + *": {
31 | marginTop: theme.spacing(2),
32 | },
33 | },
34 | shadows: ["none"],
35 | }));
36 |
37 | function Alert(props) {
38 | return ;
39 | }
40 |
41 | export default function SignUp() {
42 | const classes = useStyles();
43 |
44 | const [values, setValues] = useState({
45 | username: "",
46 | email: "",
47 | password: "",
48 | confirmPassword: "",
49 | firstName: "",
50 | lastName: "",
51 | role: "",
52 | designation: "",
53 | university: "",
54 | department: "",
55 | session: "",
56 | regNo: "",
57 | result: "",
58 | error: "",
59 | });
60 |
61 | // useEffect(() => {
62 | // axios({
63 | // method: "get",
64 | // url: apiDomain + "university/all",
65 | // })
66 | // .then((response) => {
67 | // // console.log("All Universites..");
68 |
69 | // // console.log(response.data);
70 |
71 | // const data = response.data;
72 |
73 | // if (data.status === "OK") {
74 | // setUniversities(data.result.data);
75 | // }
76 | // })
77 | // .catch((error) => console.log(error));
78 | // }, []);
79 |
80 | // console.log("API CALL DATA", universities);
81 | let history = useHistory();
82 |
83 | const obj = {
84 | role: values.role,
85 | username: values.username,
86 | email: values.email,
87 | password: values.password,
88 | repassword: values.confirmPassword,
89 | firstName: values.firstName,
90 | lastName: values.lastName,
91 | department: values.department,
92 | registrationNo: parseInt(values.regNo, 10),
93 | session: values.session,
94 | varsity: values.university,
95 | designation: values.designation,
96 | };
97 |
98 | const body = JSON.stringify(obj);
99 |
100 | const handleSignUp = (e) => {
101 | // console.log('hello')
102 | fetchData();
103 | e.preventDefault();
104 | };
105 | const fetchData = async () => {
106 | let endpoint;
107 | if (values.role === "Teacher") endpoint = "auth/create-teacher";
108 | else endpoint = "auth/create-student";
109 | const requestOptions = {
110 | method: "POST",
111 | headers: { "Content-Type": "application/json" },
112 | body: body,
113 | };
114 |
115 | const response = await fetch(`${apiDomain}${endpoint}`, requestOptions);
116 |
117 | const data = await response.json();
118 |
119 | console.log("API data", data);
120 |
121 | if (data.status === "FAILED")
122 | setValues({ ...values, ["error"]: data.result });
123 | else {
124 | setValues({ ...values, ["error"]: "" });
125 | // const userdata = {
126 | // token: data.result.jwt.token,
127 | // role: data.result.data.role.toLowerCase(),
128 | // id: data.result.data.id,
129 | // };
130 |
131 | localStorage.setItem("data", JSON.stringify(data.result.data));
132 |
133 | // console.log(userdata);
134 |
135 | // localStorage.setItem("data", JSON.stringify(userdata));
136 | history.push("/");
137 | window.location.reload();
138 | }
139 | };
140 |
141 | const handleChange = (prop) => (event) => {
142 | setValues({ ...values, [prop]: event.target.value });
143 | };
144 | // if (universities)
145 | return (
146 |
147 |
148 |
149 |
150 | Hello There!!
151 | Lets Sign Up to continue
152 |
153 |
154 | {values.error !== "" ? (
155 |
161 |
162 | {values.error}
163 |
164 |
165 | ) : null}
166 |
332 |
333 |
334 | );
335 | // else return Loading
;
336 | }
337 |
--------------------------------------------------------------------------------
/client/src/Components/Course/Course.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useRef, useState, useEffect } from "react";
3 | import { useParams } from "react-router-dom";
4 | import Sidebar from "./Sidebar";
5 | import "./Course.scss";
6 | import LinearIndeterminate from "../Generic/Loader";
7 |
8 | let userdata = localStorage.getItem("data");
9 | userdata = JSON.parse(userdata);
10 |
11 | export default function Course(props) {
12 | let { id } = useParams();
13 |
14 | const [courseData, setCourseData] = useState(null);
15 |
16 | console.log(userdata);
17 |
18 | useEffect(() => {
19 | if (userdata)
20 | axios
21 | .get(`${userdata.role}/course/${id}`)
22 | .then((response) => {
23 | const data = response.data;
24 | console.log(data);
25 | if (data.status === "OK") setCourseData(data.result.data);
26 | })
27 | .catch((error) => {
28 | console.log(error);
29 | });
30 | }, []);
31 |
32 | if (courseData)
33 | return (
34 |
35 |
36 |
37 | );
38 | else return ;
39 | }
40 |
--------------------------------------------------------------------------------
/client/src/Components/Course/Course.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/client/src/Components/Course/Course.scss
--------------------------------------------------------------------------------
/client/src/Components/Course/CreateExam/CreateExam.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "antd/dist/antd.css";
3 | import { Tabs } from "antd";
4 | import axios from "axios";
5 | import { Toast } from "react-bootstrap";
6 | import Container from "react-bootstrap/Container";
7 | import Question from "./Question";
8 | import "./CreateExam.scss";
9 |
10 | const { TabPane } = Tabs;
11 |
12 | export default class CreateCourse extends React.Component {
13 | constructor(props) {
14 | super(props);
15 | }
16 |
17 | questionIDs = [];
18 | newTabIndex = 0;
19 | quesNo = 2;
20 | totalMarks = 0;
21 | totalTime = 0;
22 |
23 | addQuestion = (id, marks, time) => {
24 | this.setState({
25 | showToast: true,
26 | examCreateMessage: "Question Created Successfully",
27 | });
28 |
29 | console.log("mcq Question Id !", id);
30 | console.log("Mark !", marks);
31 | console.log("Time!", time);
32 |
33 | this.totalMarks += marks
34 | this.totalTime += time;
35 |
36 | if (this.props.examType === "CQ")
37 | this.questionIDs.push({
38 | cqQuestionId: id,
39 | });
40 | else {
41 | this.questionIDs.push({
42 | mcqQuestionId: id,
43 | });
44 | }
45 |
46 | console.log(this.questionIDs);
47 | };
48 |
49 | createExam = (date, examName) => {
50 | console.log("Date ", date);
51 | console.log("Name ", examName);
52 |
53 | let data;
54 |
55 | if (this.props.examType === "CQ")
56 | data = JSON.stringify({
57 | course: this.props.courseData._id,
58 | cqQuestions: this.questionIDs,
59 | totalTime: this.totalTime,
60 | totalMarks: this.totalMarks,
61 | date: date,
62 | name: examName,
63 | });
64 | else
65 | data = JSON.stringify({
66 | course: this.props.courseData._id,
67 | mcqQuestions: this.questionIDs,
68 | totalTime: this.totalTime,
69 | totalMarks: this.totalMarks,
70 | date: date,
71 | name: examName,
72 | });
73 |
74 | axios({
75 | method: "POST",
76 | url: `teacher/exam/${this.props.examType === "CQ" ? "cq" : "mcq"}/create`,
77 |
78 | headers: { "Content-Type": "application/json" },
79 |
80 | data: data,
81 | })
82 | .then((response) => {
83 | console.log(response.data);
84 | if (response.data.status === "OK") {
85 | this.setState({
86 | showToast: true,
87 | examCreateMessage: "Exam Created Successfully",
88 | });
89 | } else
90 | this.setState({
91 | showToast: true,
92 | examCreateMessage: "Exam Created Successfully",
93 | });
94 | })
95 | .catch((error) => {
96 | console.log(error);
97 | this.setState({
98 | showToast: true,
99 | examCreateMessage: "Something Went Wrong!",
100 | });
101 | });
102 | };
103 |
104 | initialPanes = [
105 | {
106 | title: "Question 1",
107 | content: (
108 |
115 | ),
116 | key: "1",
117 | closable: false,
118 | },
119 | ];
120 |
121 | state = {
122 | activeKey: this.initialPanes[0].key,
123 | panes: this.initialPanes,
124 | showToast: false,
125 | examCreateMessage: null,
126 | create: true,
127 | };
128 |
129 | onChange = (activeKey) => {
130 | this.setState({ activeKey });
131 | };
132 |
133 | onEdit = (targetKey, action) => {
134 | this[action](targetKey);
135 | };
136 |
137 | add = () => {
138 | const { panes } = this.state;
139 | const activeKey = `question${this.newTabIndex++}`;
140 | const newPanes = [...panes];
141 | newPanes.push({
142 | title: `Question ${this.quesNo++}`,
143 | content: (
144 |
151 | ),
152 | key: activeKey,
153 | });
154 | this.setState({
155 | panes: newPanes,
156 | activeKey,
157 | });
158 | };
159 |
160 | remove = (targetKey) => {
161 | const { panes, activeKey } = this.state;
162 | let newActiveKey = activeKey;
163 | let lastIndex;
164 | panes.forEach((pane, i) => {
165 | if (pane.key === targetKey) {
166 | lastIndex = i - 1;
167 | }
168 | });
169 | const newPanes = panes.filter((pane) => pane.key !== targetKey);
170 | if (newPanes.length && newActiveKey === targetKey) {
171 | if (lastIndex >= 0) {
172 | newActiveKey = newPanes[lastIndex].key;
173 | } else {
174 | newActiveKey = newPanes[0].key;
175 | }
176 | }
177 | this.setState({
178 | panes: newPanes,
179 | activeKey: newActiveKey,
180 | });
181 | };
182 |
183 | render() {
184 | const { panes, activeKey } = this.state;
185 | return (
186 |
187 | this.setState({ showToast: false })}
191 | show={this.state.showToast}
192 | >
193 |
194 |
199 | Create Message
200 | just now
201 |
202 | {this.state.examCreateMessage}
203 |
204 |
210 | {panes.map((pane) => (
211 |
212 | {pane.content}
213 |
214 | ))}
215 |
216 |
217 | );
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/client/src/Components/Course/CreateExam/CreateExam.scss:
--------------------------------------------------------------------------------
1 | ul li {
2 | line-height: 35px;
3 | font-size: 125%;
4 | }
5 | .toast-modify{
6 | position: fixed;
7 | z-index: 1055;
8 | top: 100px;
9 | right: 50px;
10 | }
--------------------------------------------------------------------------------
/client/src/Components/Course/CreateExam/ExamType.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import Row from "react-bootstrap/Row";
3 | import Col from "react-bootstrap/Col";
4 | import InputLabel from "@material-ui/core/InputLabel";
5 | import MenuItem from "@material-ui/core/MenuItem";
6 | import FormControl from "@material-ui/core/FormControl";
7 | import Select from "@material-ui/core/Select";
8 | import Button from "@material-ui/core/Button";
9 | import CreateExam from "./CreateExam";
10 | import "./CreateExam.scss";
11 |
12 | const ExamType = (props) => {
13 | const [examType, setexamType] = useState("");
14 | const [create, setcreate] = useState(false);
15 |
16 | const handleChange = (event) => {
17 | setexamType(event.target.value);
18 | console.log(event.target.value);
19 | };
20 | const handleSubmit = () => {
21 | setcreate(true);
22 | };
23 |
24 | console.log(examType, create);
25 |
26 | if (!create) {
27 | return (
28 |
29 | {console.log("Hello")}
30 |
31 |
32 |
33 | Create Exam
34 |
35 |
36 |
37 |
38 | Instructions
39 |
40 | -
41 | Select exam type from below form and then click Create Exam to
42 | proceed.
43 |
44 | - You can create as many queston as you like.
45 | -
46 | For every queston you have to set a specific time limit for
47 | your student to answer that question.
48 |
49 | - Also you have to specify marks for every question.
50 | - When your question set is ready click Lock Exam.
51 | -
52 | Then you'll need to give your exam a name and a start
53 | schedule.
54 |
55 |
56 |
57 |
58 |
83 |
84 |
85 | );
86 | } else
87 | return ;
88 | };
89 |
90 | export default ExamType;
91 |
--------------------------------------------------------------------------------
/client/src/Components/Course/Exams.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Button } from "react-bootstrap";
3 |
4 | const Exams = (props) => {
5 | console.log(props.userInfo.role);
6 |
7 | const exams = [];
8 |
9 | if (props.courseData.cqExams) {
10 | props.courseData.cqExams.forEach((exam, j) => {
11 | if (
12 | new Date(exam.examId.date).getTime() + exam.examId.totalTime * 1000 <
13 | new Date().getTime()
14 | )
15 | exams.push({
16 | _id: exam.examId._id,
17 | name: exam.examId.name,
18 | courseName: props.courseData.name,
19 | date: new Date(exam.examId.date),
20 | totalMarks: exam.examId.totalMarks,
21 | examType: "cq",
22 | when: "previous",
23 | totalTime: exam.examId.totalTime,
24 | createdBy: props.courseData.createdBy.firstName
25 | ? props.courseData.createdBy.firstName
26 | : "" + " " + props.courseData.createdBy.lastName
27 | ? props.courseData.createdBy.lastName
28 | : "" + " " + props.courseData.createdBy.username,
29 | });
30 | else {
31 | exams.push({
32 | _id: exam.examId._id,
33 | name: exam.examId.name,
34 | courseName: props.courseData.name,
35 | date: new Date(exam.examId.date),
36 | totalMarks: exam.examId.totalMarks,
37 | totalTime: exam.examId.totalTime,
38 | examType: "cq",
39 | when: "upcoming",
40 | createdBy: props.courseData.createdBy.firstName
41 | ? props.courseData.createdBy.firstName
42 | : "" + " " + props.courseData.createdBy.lastName
43 | ? props.courseData.createdBy.lastName
44 | : "" + " " + props.courseData.createdBy.username,
45 | });
46 | }
47 | });
48 | }
49 |
50 | if (props.courseData.mcqExams) {
51 | props.courseData.mcqExams.forEach((exam, j) => {
52 | if (
53 | new Date(exam.examId.date).getTime() + exam.examId.totalTime * 1000 >
54 | new Date().getTime()
55 | )
56 | exams.push({
57 | _id: exam.examId._id,
58 | name: exam.examId.name,
59 | courseName: props.courseData.name,
60 | date: new Date(exam.examId.date),
61 | totalMarks: exam.examId.totalMarks,
62 | totalTime: exam.examId.totalTime,
63 | examType: "mcq",
64 | when: "upcoming",
65 | createdBy: props.courseData.createdBy.firstName
66 | ? props.courseData.createdBy.firstName
67 | : "" + " " + props.courseData.createdBy.lastName
68 | ? props.courseData.createdBy.lastName
69 | : "" + " " + props.courseData.createdBy.username,
70 | });
71 | else {
72 | exams.push({
73 | _id: exam.examId._id,
74 | name: exam.examId.name,
75 | courseName: props.courseData.name,
76 | date: new Date(exam.examId.date),
77 | totalMarks: exam.examId.totalMarks,
78 | totalTime: exam.examId.totalTime,
79 | examType: "mcq",
80 | when: "previous",
81 | createdBy: props.courseData.createdBy.firstName
82 | ? props.courseData.createdBy.firstName
83 | : "" + " " + props.courseData.createdBy.lastName
84 | ? props.courseData.createdBy.lastName
85 | : "" + " " + props.courseData.createdBy.username,
86 | });
87 | }
88 | });
89 | }
90 |
91 | exams.sort(function (a, b) {
92 | return b.date.getTime() - a.date.getTime();
93 | });
94 |
95 | let x = 1;
96 | const tableBody = exams.map((exam) => {
97 | console.log("exam->", exam);
98 | return (
99 | <>
100 |
101 | {x++} |
102 | {exam.name} |
103 | {exam.examType} |
104 | {exam.totalMarks} |
105 | {`${Math.round(exam.totalTime / 60)} min : ${
106 | exam.totalTime % 60
107 | } sec`} |
108 | {exam.when} |
109 | {exam.date.toString()} |
110 | {props.userInfo.role === "Teacher" ? (
111 |
112 |
115 | |
116 | ) : null}
117 |
118 |
119 |
122 | |
123 |
124 | >
125 | );
126 | });
127 |
128 | return (
129 |
133 |
134 |
135 | # |
136 | Exam Name |
137 | Exam Type |
138 | Total Marks |
139 | Total Time |
140 | Condition |
141 | Date |
142 | {props.userInfo.role === "Teacher" ? Check | : null}
143 | Action |
144 |
145 |
146 |
147 | {tableBody}
148 |
149 | );
150 | };
151 |
152 | export default Exams;
153 |
--------------------------------------------------------------------------------
/client/src/Components/Course/Info.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Container from "react-bootstrap/Container";
3 | import Row from "react-bootstrap/Row";
4 | import Col from "react-bootstrap/Col";
5 |
6 | export default function(props) {
7 | const name = props.courseData.name;
8 | return (
9 |
10 |
11 |
12 | Course Info
13 |
14 |
15 |
16 |
17 | Name
18 |
19 |
20 | {name}
21 |
22 |
23 |
24 |
25 | Department
26 |
27 |
28 | {props.userInfo.department}
29 |
30 |
31 |
32 |
33 | University
34 |
35 |
36 | {props.userInfo.varsity}
37 |
38 |
39 |
40 | );
41 | }
--------------------------------------------------------------------------------
/client/src/Components/Course/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React, { useState ,useEffect} from "react";
2 | import Row from "react-bootstrap/Row";
3 | import Col from "react-bootstrap/Col";
4 | import { IoCreate } from "react-icons/io5";
5 | import { IoClipboard } from "react-icons/io5";
6 | import { FaAngleDoubleRight } from "react-icons/fa";
7 | import { FaChalkboardTeacher } from "react-icons/fa";
8 | import { FaUsers } from "react-icons/fa";
9 | import { FaInfoCircle } from "react-icons/fa";
10 | import "./Sidebar.scss";
11 | import ExamType from "./CreateExam/ExamType";
12 | import Students from './Students';
13 | import Exams from "./Exams";
14 | import Teacher from "./Teacher";
15 | import Info from "./Info";
16 |
17 | export default function Sidebar(props) {
18 |
19 |
20 |
21 | let userdata;
22 | userdata = localStorage.getItem("data");
23 | userdata = JSON.parse(userdata);
24 |
25 | console.log(props.courseData);
26 |
27 |
28 | let displayContent;
29 |
30 | const [sidebar, setSidebar] = useState(false);
31 | const showSidebar = () => setSidebar(!sidebar);
32 |
33 | const [value, setValue] = React.useState(0);
34 |
35 | const handleChange = (event, newValue) => {
36 | setValue(newValue);
37 | };
38 | const [content, setContent] = useState("");
39 | const handleClick = (prop) => (event) => {
40 | setContent(prop);
41 | };
42 | console.log(content);
43 | if (content === "createExam")
44 | displayContent = (
45 |
46 | );
47 | else if (content === "exams")
48 | displayContent = (
49 |
54 | );
55 | else if (content === "students")
56 | displayContent = (
57 |
62 | );
63 | else if(content === "teacher") {
64 | displayContent = (
65 |
70 | );
71 | }
72 | else if(content === "info") {
73 | displayContent = (
74 |
79 | );
80 | }
81 |
82 | return (
83 |
84 |
159 |
160 | {displayContent}
161 |
162 |
163 | );
164 | }
165 |
--------------------------------------------------------------------------------
/client/src/Components/Course/Sidebar.scss:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | list-style: none;
5 | text-decoration: none;
6 | }
7 | :root {
8 | font-size: 16px;
9 | font-family: "Open Sans";
10 | --transition-speed: 600ms;
11 | }
12 | .parent {
13 | width: 100%;
14 | display: flex;
15 | flex-direction: column;
16 | }
17 | .sidebar {
18 | width: 4.5rem;
19 | height: 100%;
20 | position: fixed;
21 | background-color: #2c2c2c;
22 | color: white;
23 | transition: width 400ms ease;
24 | overflow-x: hidden;
25 | overflow-y: auto;
26 | z-index: 1;
27 | &__logo {
28 | font-weight: bold;
29 | text-transform: uppercase;
30 | color: blanchedalmond;
31 | background-color: #3f7cac;
32 | letter-spacing: 0.15ch;
33 | width: 100%;
34 | font-size: 1.45rem;
35 | .sidebar__item__icon {
36 | transform: rotate(0deg);
37 | transition: transform var(--transition-speed);
38 | &:hover,
39 | &:active,
40 | &:focus {
41 | color: #f5faff;
42 | }
43 | }
44 | .sidebar__item__link {
45 | filter: grayscale(0%) opacity(1);
46 | &:hover,
47 | &:focus {
48 | filter: grayscale(0%) opacity(1);
49 | color: #f5faff;
50 | }
51 | }
52 | }
53 | &__nav {
54 | list-style: none;
55 | padding: 0;
56 | margin: 0;
57 | display: flex;
58 | flex-direction: column;
59 | align-items: center;
60 | height: 100%;
61 | }
62 | &__item {
63 | width: 100%;
64 | &__link {
65 | display: flex;
66 | align-items: center;
67 | height: 5rem;
68 | color: white;
69 | text-decoration: none;
70 | transition: var(--transition-speed);
71 | filter: grayscale(100%) opacity(0.7);
72 | transition: var(--transition-speed);
73 | &:hover,
74 | &:active,
75 | &:focus {
76 | text-decoration: none;
77 | filter: grayscale(0%) opacity(1);
78 | color: #ffce47;
79 | background-color: rgba(238, 232, 232, 0.2);
80 | }
81 | }
82 | &__icon {
83 | font-size: 2rem;
84 | min-width: 2rem;
85 | margin: 0 1.1rem;
86 | }
87 | &__text {
88 | display: none;
89 | margin-left: 0.5rem;
90 | font-size: 1.15em;
91 | transition: var(--transition-speed);
92 | }
93 | &:last-child {
94 | margin-top: auto;
95 | margin-bottom: 52px;
96 | }
97 | }
98 | }
99 | .sidebar.active {
100 | width: 14rem;
101 | .sidebar__logo {
102 | .sidebar__item__link {
103 | padding-left: 0.55em;
104 | }
105 | .sidebar__item__icon {
106 | transform: rotate(-180deg);
107 | }
108 | }
109 | .sidebar__item__text {
110 | display: inline;
111 | color: white;
112 | }
113 | }
114 | .content__large {
115 | transition: padding-left var(--transition-speed);
116 | padding-left: 4.5rem;
117 | }
118 | .content__small {
119 | transition: padding-left 400ms;
120 | padding-left: 14.5rem;
121 | }
122 |
123 | :target {
124 | text-decoration: none;
125 | filter: grayscale(0%) opacity(1);
126 | color: #ffce47;
127 | background-color: rgba(238, 232, 232, 0.2);
128 | }
--------------------------------------------------------------------------------
/client/src/Components/Course/Students.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Col, Container, Row, Card, Alert, Table } from "react-bootstrap";
3 | import MenuItem from "@material-ui/core/MenuItem";
4 | import { Box, CardContent, MenuList, Typography } from "@material-ui/core";
5 |
6 | import {
7 | Button,
8 | Modal,
9 | Form,
10 | Spinner,
11 | Jumbotron,
12 | Tab,
13 | TabContainer,
14 | ListGroup,
15 | TabContent,
16 | TabPane,
17 | } from "react-bootstrap";
18 |
19 | const Students = (props) => {
20 | console.log(props.userInfo);
21 | console.log(props.courseData);
22 |
23 | let x = 1;
24 | const tableBody = props.courseData.students.map((students) => {
25 | return (
26 | <>
27 |
28 | {x++} |
29 | {/* */}
30 | {/*
31 | {x == 2 ? "👑" : ""}
32 | */}
33 | {/* {students.student} */}
34 | {/* | */}
35 | {/* {exam.examType} |
36 | {exam.totalMarks} |
37 | {`${Math.round(exam.totalTime / 60)} min : ${
38 | exam.totalTime % 60
39 | } sec`} |
40 | {exam.when} |
41 | {exam.date.toString()} |
42 | {props.userInfo.role === "Teacher" ? (
43 |
44 |
47 | |
48 | ) : (
49 | null
50 | )} */}
51 |
52 |
53 |
56 | |
57 |
58 | {/*
59 |
62 | | */}
63 |
64 | >
65 | );
66 | });
67 |
68 | return (
69 |
73 |
74 |
75 | # |
76 | {/* Exam Name |
77 | Exam Type |
78 | Total Marks |
79 | Total Time |
80 |
81 | Condition |
82 | Date |
83 | {props.userInfo.role === "Teacher" ? Check | : null} */}
84 | Action |
85 |
86 |
87 |
88 | {tableBody}
89 |
90 | );
91 | };
92 |
93 | export default Students;
94 |
--------------------------------------------------------------------------------
/client/src/Components/Course/Teacher.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Container from "react-bootstrap/Container";
3 | import Row from "react-bootstrap/Row";
4 | import Col from "react-bootstrap/Col";
5 |
6 | export default function(props) {
7 | const name = `${props.userInfo.firstName} ${props.userInfo.lastName}`
8 | return (
9 |
10 |
11 |
12 | Teacher Info
13 |
14 |
15 |
16 |
17 | Name
18 |
19 |
20 | {name}
21 |
22 |
23 |
24 |
25 | Department
26 |
27 |
28 | {props.userInfo.department}
29 |
30 |
31 |
32 |
33 | University
34 |
35 |
36 | {props.userInfo.varsity}
37 |
38 |
39 |
40 | );
41 | }
--------------------------------------------------------------------------------
/client/src/Components/Exam/Exam.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState, useEffect } from "react";
2 | import axios from "axios";
3 | import {
4 | Button,
5 | Card,
6 | CardActions,
7 | CardContent,
8 | CircularProgress,
9 | Container,
10 | Divider,
11 | Grid,
12 | List,
13 | ListItem,
14 | makeStyles,
15 | Menu,
16 | MenuItem,
17 | Paper,
18 | TextField,
19 | Typography,
20 | } from "@material-ui/core";
21 | import { useParams } from "react-router-dom";
22 |
23 | const useStyles = makeStyles((theme) => ({
24 | root: {
25 | display: "flex",
26 | "& > * + *": {
27 | marginLeft: theme.spacing(2),
28 | },
29 | },
30 | }));
31 |
32 | export default function Exam(props) {
33 | // const { match } = props;
34 |
35 | // console.log("Exam id",match);
36 | console.log("props... ", props);
37 |
38 | let { id } = useParams();
39 | console.log("ID", id);
40 |
41 | const [examData, setExamData] = useState(null);
42 |
43 | const [timer, setTimer] = useState(null);
44 |
45 | const classes = useStyles();
46 |
47 | useEffect(() => {
48 | if (props.userInfo)
49 | axios.get(`${props.userInfo.role}/exam/${id}`).then((response) => {
50 | const data = response.data;
51 | setExamData(data.result.data);
52 | });
53 | }, []);
54 |
55 | console.log("Exam Data", examData);
56 |
57 | let examQuestionUi;
58 |
59 | if (examData && examData.mcqQuestions) {
60 | examQuestionUi = examData.mcqQuestions.map((question) => {
61 | return (
62 |
63 |
64 | {question.mcqQuestionId.description}
65 |
66 | {question.mcqQuestionId.mainQuestion}
67 |
68 |
69 | {question.mcqQuestionId.options.map((options) => {
70 | return (
71 |
72 | {options.option}
73 |
74 | );
75 | })}
76 |
77 |
78 |
79 |
80 | );
81 | });
82 | } else if (examData && examData.cqQuestions) {
83 | examQuestionUi = examData.cqQuestions.map((question) => {
84 | return (
85 |
86 |
87 | {question.cqQuestionId.description}
88 |
89 | {question.cqQuestionId.mainQuestion}
90 |
97 |
98 |
99 |
100 | );
101 | });
102 | }
103 |
104 | let x = 0;
105 |
106 | if (examData)
107 | setInterval(() => {
108 | const date = new Date();
109 | setTimer(date.getSeconds());
110 | }, 1000);
111 |
112 | if (examData)
113 | return (
114 |
115 |
116 |
117 |
118 |
119 | {examData.name}
120 |
121 |
122 |
123 |
124 |
125 | {" "}
126 | {timer}
127 |
128 |
129 |
130 |
131 | {examQuestionUi}
132 |
133 |
134 | );
135 | else return ;
136 | }
137 |
--------------------------------------------------------------------------------
/client/src/Components/Generic/Forms.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import TextField from '@material-ui/core/TextField';
3 | import IconButton from "@material-ui/core/IconButton";
4 | import OutlinedInput from "@material-ui/core/OutlinedInput";
5 | import InputLabel from "@material-ui/core/InputLabel";
6 | import InputAdornment from "@material-ui/core/InputAdornment";
7 | import FormControl from "@material-ui/core/FormControl";
8 | import Visibility from "@material-ui/icons/Visibility";
9 | import VisibilityOff from "@material-ui/icons/VisibilityOff";
10 | import MenuItem from "@material-ui/core/MenuItem";
11 | import Select from "@material-ui/core/Select";
12 | import axios from "axios";
13 | import "./Forms.scss";
14 |
15 | const apiDomain = "http://localhost:8080/";
16 |
17 | const TextFieldForm = (props) => (
18 |
33 | )
34 |
35 | const TextForm = (props) => (
36 |
42 | {props.label}
43 |
49 |
50 | );
51 |
52 | const PasswordForm = (props) => {
53 | const [showPassword, setShowPassword] = useState(false);
54 |
55 | const handleClickShowPassword = () => {
56 | setShowPassword(!showPassword);
57 | };
58 |
59 | const handleMouseDownPassword = (event) => {
60 | event.preventDefault();
61 | };
62 | return (
63 |
69 | {props.label}
70 |
77 |
83 | {showPassword ? : }
84 |
85 |
86 | }
87 | labelWidth={props.labelWidth}
88 | />
89 |
90 | );
91 | };
92 |
93 | const Forms = (props) => {
94 | const type = props.type;
95 |
96 | const [universities, setUniversities] = useState(null);
97 | const [isApiLoaded, setIsApiLoaded] = useState(true);
98 |
99 | // console.log(props);
100 |
101 | useEffect(() => {
102 | axios({
103 | method: "get",
104 | url: apiDomain + "university/all",
105 | })
106 | .then((response) => {
107 | // console.log("All Universites..");
108 |
109 | // console.log(response.data);
110 |
111 | const data = response.data;
112 |
113 | if (data.status === "OK") {
114 | setUniversities(data.result.data.universities);
115 | }
116 | })
117 | .catch((error) => {
118 | console.log(error);
119 | setIsApiLoaded(false);
120 | });
121 | }, []);
122 |
123 | const SelectForm = (props) => {
124 | // console.log("COMPONENT : select form");
125 | let items = [];
126 | const id = props.id;
127 |
128 | if (universities) {
129 | // console.log("Univbersity", universities);
130 |
131 | // for (let i = 0; i < universities.length; i++) {
132 | // console.log("Loop");
133 | // console.log(universities[i]);
134 | // }
135 |
136 | if (id === "role")
137 | items = [
138 | {
139 | id: "Teacher",
140 | value: "Teacher",
141 | },
142 | {
143 | id: "Student",
144 | value: "Student",
145 | },
146 | ];
147 | else if (id === "university") {
148 | items = [];
149 | universities.forEach((element) => {
150 | items.push({
151 | id: element._id,
152 | value: element.shortform,
153 | });
154 | });
155 | } else if (id === "department") {
156 | items = [];
157 |
158 | if (props.selectedUniversity) {
159 | // console.log("Selected University ", props.selectedUniversity);
160 | universities.forEach((element) => {
161 | if (element._id === props.selectedUniversity) {
162 | element.departments.forEach((dept) => {
163 | // console.log(dept);
164 | items.push({
165 | id: dept._id,
166 | value: dept.shortform,
167 | });
168 | });
169 | }
170 | });
171 | }
172 | } else if (id === "session") {
173 | items = [];
174 | items = [
175 | {
176 | id: "2016-2017",
177 | value: "2016-2017",
178 | },
179 | {
180 | id: "2017-2018",
181 | value: "2017-2018",
182 | },
183 | {
184 | id: "2018-2019",
185 | value: "2018-2019",
186 | },
187 | {
188 | id: "2020-2021",
189 | value: "2020-2021",
190 | },
191 | ];
192 | } else if (id === "designation") {
193 | items = [];
194 | items = [
195 | {
196 | id: "Department Head",
197 | value: "Department Head",
198 | },
199 | {
200 | id: "Professor",
201 | value: "Professor",
202 | },
203 | {
204 | id: "Assistant Professor",
205 | value: "Assistant Professor",
206 | },
207 | {
208 | id: "Lecturer",
209 | value: "Lecturer",
210 | },
211 | ];
212 | } else if(id === "options") {
213 | items = [];
214 | items = [
215 | {
216 | id: "optA",
217 | value: "A",
218 | },
219 | {
220 | id: "optB",
221 | value: "B",
222 | },
223 | {
224 | id: "optC",
225 | value: "C",
226 | },
227 | {
228 | id: "optD",
229 | value: "D",
230 | },
231 | ];
232 | }
233 | }
234 |
235 | const menuItems = items.map((item, i) => {
236 | // console.log(items);
237 | return (
238 |
241 | );
242 | });
243 |
244 | return (
245 |
252 | {props.label}
253 |
264 |
265 | );
266 | };
267 |
268 | if (type === "text") {
269 | return ;
270 | } else if (type === "password") {
271 | return ;
272 | } else if (type === "select") {
273 | return ;
274 | } else {
275 | return
276 | }
277 | };
278 |
279 | export default Forms;
280 |
--------------------------------------------------------------------------------
/client/src/Components/Generic/Forms.scss:
--------------------------------------------------------------------------------
1 | .sign {
2 | /* width: 50%;
3 | margin: 0 auto; */
4 | display: flex;
5 | justify-content: center;
6 | }
7 | .errorMsg {
8 | background-color: rgb(250, 214, 214);
9 | margin: 20px;
10 | padding: 7px 10px;
11 | border: 2px solid rgb(255, 197, 197);
12 | border-radius: 5px;
13 | color: rgb(211, 12, 12);
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/Components/Generic/Loader.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { makeStyles } from "@material-ui/core/styles";
3 | import LinearProgress from "@material-ui/core/LinearProgress";
4 |
5 | const useStyles = makeStyles((theme) => ({
6 | root: {
7 | width: "100%",
8 | "& > * + *": {
9 | marginTop: theme.spacing(2),
10 | },
11 | },
12 | }));
13 |
14 | const LinearIndeterminate = () => {
15 | const classes = useStyles();
16 |
17 | return (
18 |
19 |
20 |
21 |
22 | );
23 | };
24 |
25 | export default LinearIndeterminate;
26 |
--------------------------------------------------------------------------------
/client/src/Components/Generic/Notification.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Button from "@material-ui/core/Button";
3 | import { SnackbarProvider, useSnackbar } from "notistack";
4 |
5 | function MyApp() {
6 | const { enqueueSnackbar } = useSnackbar();
7 |
8 | const handleClick = () => {
9 | enqueueSnackbar("I love snacks.");
10 | };
11 |
12 | const handleClickVariant = (variant) => () => {
13 | // variant could be success, error, warning, info, or default
14 | enqueueSnackbar("This is a success message!", { variant });
15 | };
16 |
17 | return (
18 |
19 |
20 |
23 |
24 | );
25 | }
26 |
27 | export default function IntegrationNotistack(props) {
28 | return (
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/client/src/Components/Home/Home.scss:
--------------------------------------------------------------------------------
1 | body {
2 | height: 100vh;
3 | width: 100vh;
4 | }
5 |
6 | .upcoming {
7 | height: 100vh;
8 | hr {
9 | background-color: #E2EBF3;
10 | }
11 | &__first {
12 | // margin-top: 3%;
13 | height: 20.1rem;
14 | background-color: white;
15 | border-radius: 10px;
16 | margin-bottom: 3%;
17 | }
18 | &__next {
19 | border-radius: 6px;
20 | margin-bottom: 10px;
21 | width: 100%;
22 | background-color: white;
23 | text-decoration: none;
24 |
25 | .examName {
26 | font-size: 130%;
27 | color: black;
28 | text-decoration: none;
29 | font-family: 'Open Sans', sans-serif;
30 | }
31 | }
32 | }
33 | .board {
34 | font-size: 30px;
35 | }
36 | .examName {
37 | font-size: 130%;
38 | text-decoration: none;
39 | font-family: 'Open Sans', sans-serif;
40 | }
41 | .examSchedule {
42 | font-size: 16px;
43 | color: rgb(117, 117, 117);
44 | }
45 | .infos {
46 | font-size: 120%;
47 | }
48 | .sideExams {
49 | padding-bottom: 10px;
50 | }
51 | .leftside, .rightside {
52 | height: 100vh;
53 | background-color: white;
54 | color: black;
55 | text-decoration: none;
56 | overflow:hidden;
57 | hr {
58 | background-color: #F5F5F5;
59 | }
60 | .examName {
61 | font-size: 120%;
62 | color: black;
63 | text-decoration: none;
64 | font-family: 'Open Sans', sans-serif;
65 | }
66 | }
67 | .leftside {
68 | border-right: 1px solid #E2EBF3;
69 | }
70 | .rightHeading, .leftHeading, .centerHeading {
71 | font-family: 'Open Sans', sans-serif;
72 | }
--------------------------------------------------------------------------------
/client/src/Components/LandingPage/LandingPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Container from "react-bootstrap/Container";
3 | import Row from "react-bootstrap/Row";
4 | import Col from "react-bootstrap/Col";
5 | import './LandingPage.scss';
6 |
7 | export default function(){
8 | return (
9 |
10 |
11 |
12 |
13 |
14 | paper
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
--------------------------------------------------------------------------------
/client/src/Components/LandingPage/LandingPage.scss:
--------------------------------------------------------------------------------
1 | .root {
2 | }
3 | .header {
4 | background-image: url('pic.jpg');
5 | background-position: center bottom;
6 | background-repeat: no-repeat;
7 | background-size: contain, 100%;
8 | height: 100vh;
9 | background-color: black;
10 | color: white;
11 | }
12 | .heading {
13 | color: white;
14 | font-size: 250%;
15 | margin: 7% 0 0 10% ;
16 | }
--------------------------------------------------------------------------------
/client/src/Components/LandingPage/pic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/client/src/Components/LandingPage/pic.jpg
--------------------------------------------------------------------------------
/client/src/Components/Layout/Layout.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | Button,
4 | Col,
5 | Container,
6 | Row,
7 | Modal,
8 | Form,
9 | } from "react-bootstrap";
10 | import Select from "@material-ui/core/Select";
11 | import InputLabel from "@material-ui/core/InputLabel";
12 | import MenuItem from "@material-ui/core/MenuItem";
13 | import FormControl from "@material-ui/core/FormControl";
14 |
15 | const Layout = (props) => {
16 | const [showModal, setShowModal] = useState(true);
17 |
18 | const handleCloseModal = () => setShowModal(false);
19 | const handleShowModal = () => setShowModal(true);
20 |
21 | const SelectForm = () => {
22 | let items = [];
23 |
24 | if (props.universityInfo) {
25 | props.universityInfo.forEach((element) => {
26 | if (element.shortform === props.userInfo.varsity) {
27 | element.departments.forEach((dept) => {
28 | // console.log(dept);
29 | items.push({
30 | id: dept._id,
31 | value: dept.shortform,
32 | });
33 | });
34 | }
35 | });
36 | }
37 |
38 | const menuItems = items.map((item, i) => {
39 | // console.log(items);
40 | return (
41 |
44 | );
45 | });
46 |
47 | return (
48 |
49 | {props.label}
50 |
56 |
57 | );
58 | };
59 |
60 | const createCourseModal = (
61 |
67 |
68 | Create Course
69 |
70 |
71 |
94 |
95 |
96 |
99 |
100 |
101 |
102 | );
103 |
104 | return (
105 |
106 | ;
107 |
108 | );
109 | };
110 |
111 | export default Layout;
112 |
--------------------------------------------------------------------------------
/client/src/Components/LiveExam/LiveExam.scss:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #f6f8fa;
3 | }
4 | .root {
5 | margin-top: 4%;
6 | }
7 |
8 | .noselect {
9 | -webkit-touch-callout: none; /* iOS Safari */
10 | -webkit-user-select: none; /* Safari */
11 | -khtml-user-select: none; /* Konqueror HTML */
12 | -moz-user-select: none; /* Old versions of Firefox */
13 | -ms-user-select: none; /* Internet Explorer/Edge */
14 | user-select: none; /* Non-prefixed version, currently
15 | supported by Chrome, Edge, Opera and Firefox */
16 | }
17 |
18 | .exam {
19 | background-color: white;
20 | box-shadow: 0px 0px 11px 2px rgba(194, 194, 194, 1);
21 | &__title {
22 | background-color: #292929;
23 | padding-top: 7px;
24 | padding-bottom: 5px;
25 | h4 {
26 | color: white;
27 | }
28 | }
29 | &__description {
30 | border-bottom: 2px solid #e9ebed;
31 | }
32 | &__question {
33 | padding-top: 7px;
34 | padding-bottom: 5px;
35 | }
36 | &__options {
37 | background-color: #f4f5f9;
38 |
39 | .option {
40 | border-bottom: 2px solid #e2ebf3;
41 | }
42 | .option:first-child {
43 | border-top: 2px solid #e2ebf3;
44 | }
45 | }
46 | &__buttons {
47 | padding: 10px 0px 10px 0px;
48 | .timer {
49 | margin-top: 1%;
50 | font-size: large;
51 | }
52 | }
53 | }
54 | .feedback {
55 | padding-top: 1%;
56 | background-color: #f9f9f9;
57 | }
58 |
--------------------------------------------------------------------------------
/client/src/Components/LiveExam/Loading.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import { makeStyles } from '@material-ui/core/styles';
4 | import CircularProgress from '@material-ui/core/CircularProgress';
5 | import { green } from '@material-ui/core/colors';
6 | import Button from '@material-ui/core/Button';
7 | import Fab from '@material-ui/core/Fab';
8 | import CheckIcon from '@material-ui/icons/Check';
9 | import SaveIcon from '@material-ui/icons/Save';
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | root: {
13 | display: 'flex',
14 | alignItems: 'center',
15 | },
16 | wrapper: {
17 | margin: theme.spacing(1),
18 | position: 'relative',
19 | },
20 | buttonSuccess: {
21 | backgroundColor: green[500],
22 | '&:hover': {
23 | backgroundColor: green[700],
24 | },
25 | },
26 | fabProgress: {
27 | color: green[500],
28 | position: 'absolute',
29 | top: -6,
30 | left: -6,
31 | zIndex: 1,
32 | },
33 | buttonProgress: {
34 | color: green[500],
35 | position: 'absolute',
36 | top: '50%',
37 | left: '50%',
38 | marginTop: -12,
39 | marginLeft: -12,
40 | },
41 | }));
42 |
43 | const CircularIntegration = () => {
44 | const classes = useStyles();
45 | const [loading, setLoading] = React.useState(false);
46 | const [success, setSuccess] = React.useState(false);
47 | const timer = React.useRef();
48 |
49 | const buttonClassname = clsx({
50 | [classes.buttonSuccess]: success,
51 | });
52 |
53 | React.useEffect(() => {
54 | return () => {
55 | clearTimeout(timer.current);
56 | };
57 | }, []);
58 |
59 | const handleButtonClick = () => {
60 | if (!loading) {
61 | setSuccess(false);
62 | setLoading(true);
63 | timer.current = window.setTimeout(() => {
64 | setSuccess(true);
65 | setLoading(false);
66 | }, 2000);
67 | }
68 | };
69 |
70 | return (
71 |
72 |
73 |
79 | {success ? : }
80 |
81 | {loading && }
82 |
83 |
84 |
93 | {loading && }
94 |
95 |
96 | );
97 | }
98 |
99 |
100 | export default CircularIntegration;
--------------------------------------------------------------------------------
/client/src/Components/LiveExam/Result.js:
--------------------------------------------------------------------------------
1 | import { Button } from "@material-ui/core";
2 | import React from "react";
3 | import { Col, Container, Row, Alert } from "react-bootstrap";
4 | import LinearIndeterminate from "../Generic/Loader";
5 | import "./LiveExam.scss";
6 |
7 | const Result = (props) => {
8 | if (props.result)
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | {/* */}
17 | Exam Finished!
18 |
19 |
20 | {props.examType === "mcq" ? (
21 |
0 ? "success" : "danger"}
23 | >
24 | {props.result.mark > 0
25 | ? `Congrats You have Scored ${props.result.mark}`
26 | : `Oho! You have Scored ${props.result.mark}`}
27 |
28 | ) : (
29 |
30 | You will be notified when result publish.
31 |
32 | )}
33 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | );
49 | else return ;
50 | };
51 |
52 | export default Result;
53 |
--------------------------------------------------------------------------------
/client/src/Components/LiveExam/ResultLoading.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import { makeStyles } from '@material-ui/core/styles';
4 | import CircularProgress from '@material-ui/core/CircularProgress';
5 | import { green } from '@material-ui/core/colors';
6 | import Button from '@material-ui/core/Button';
7 | import Fab from '@material-ui/core/Fab';
8 | import CheckIcon from '@material-ui/icons/Check';
9 | import SaveIcon from '@material-ui/icons/Save';
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | root: {
13 | display: 'flex',
14 | alignItems: 'center',
15 | },
16 | wrapper: {
17 | margin: theme.spacing(1),
18 | position: 'relative',
19 | },
20 | buttonSuccess: {
21 | backgroundColor: green[500],
22 | '&:hover': {
23 | backgroundColor: green[700],
24 | },
25 | },
26 | fabProgress: {
27 | color: green[500],
28 | position: 'absolute',
29 | top: -6,
30 | left: -6,
31 | zIndex: 1,
32 | },
33 | buttonProgress: {
34 | color: green[500],
35 | position: 'absolute',
36 | top: '50%',
37 | left: '50%',
38 | marginTop: -12,
39 | marginLeft: -12,
40 | },
41 | }));
42 |
43 | export default function CircularIntegration() {
44 | const classes = useStyles();
45 | const [loading, setLoading] = React.useState(false);
46 | const [success, setSuccess] = React.useState(false);
47 | const timer = React.useRef();
48 |
49 | const buttonClassname = clsx({
50 | [classes.buttonSuccess]: success,
51 | });
52 |
53 | React.useEffect(() => {
54 | return () => {
55 | clearTimeout(timer.current);
56 | };
57 | }, []);
58 |
59 | const handleButtonClick = () => {
60 | if (!loading) {
61 | setSuccess(false);
62 | setLoading(true);
63 | timer.current = window.setTimeout(() => {
64 | setSuccess(true);
65 | setLoading(false);
66 | }, 2000);
67 | }
68 | };
69 |
70 | return (
71 |
72 |
73 |
79 | {success ? : }
80 |
81 | {loading && }
82 |
83 |
84 |
93 | {loading && }
94 |
95 |
96 | );
97 | }
98 |
--------------------------------------------------------------------------------
/client/src/Components/Notifications/Notification.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from "react";
2 | import { Link } from "react-router-dom";
3 | import Navbar from "react-bootstrap/Navbar";
4 | import Nav from "react-bootstrap/Nav";
5 | import IconButton from "@material-ui/core/IconButton";
6 | import Badge from "@material-ui/core/Badge";
7 | import MenuItem from "@material-ui/core/MenuItem";
8 | import Menu from "@material-ui/core/Menu";
9 | import { FaUserAlt } from "react-icons/fa";
10 | import { FaBell } from "react-icons/fa";
11 | import { useHistory } from "react-router-dom";
12 | import { Spinner } from "react-bootstrap";
13 | import socketIOClient from "socket.io-client";
14 | import axios from "axios";
15 | import { Snackbar } from "@material-ui/core";
16 | import Alert from "@material-ui/lab/Alert";
17 | const ENDPOINT = "http://localhost:8080";
18 |
19 | export default function Notifications(params) {
20 |
21 | const [notifies, setnotifies] = useState(null);
22 |
23 |
24 | useEffect(() => {
25 | const socket = socketIOClient(ENDPOINT);
26 | axios
27 | .get("/notifications")
28 | .then((result) => {
29 | console.log("Notifications ", result.data.result.data);
30 | setnotifies(result.data.result.data);
31 | })
32 | .catch((error) => {
33 | console.log(error);
34 | });
35 |
36 | // if (userdata) {
37 | // console.log(userdata.department);
38 | // socket.on(userdata.department, (data, error) => {
39 | // // setResponse(data);
40 | // console.log("data from socket", data);
41 | // console.log("data from socket", error);
42 | // if (userdata.role === "Student") {
43 | // const bal = notifies;
44 | // bal.push(data);
45 | // // setnotifies(data);
46 |
47 | // if (userdata.role === "Teacher") {
48 | // if (data.type === "course")
49 | // setsnackbarMsg(`New Course ${data.name} Invitation For You.`);
50 | // else if (data.type === `exam`)
51 | // setsnackbarMsg(`A new exam ${data.name} is set to your course.`);
52 | // else if (data.type === `result`)
53 | // setsnackbarMsg(
54 | // `Your CQ Exam (${data.name}) result has been published.`
55 | // );
56 | // }
57 | // }
58 | // });
59 | // }
60 | }, []);
61 |
62 | const joinCourse = (courseID) => {
63 |
64 | console.log(courseID);
65 |
66 | axios({
67 | method: "POST",
68 | url: `student/course/add`,
69 |
70 | headers: { "Content-Type": "application/json" },
71 | data: JSON.stringify({
72 | course: courseID,
73 | }),
74 | })
75 | .then((response) => {
76 | console.log(response.data);
77 | if (response.data.status === "OK") {
78 | // window.location.reload();
79 | }
80 | })
81 | .catch((error) => {
82 | console.log(error);
83 | });
84 | };
85 |
86 | let notificationsUI ;
87 | if (notifies)
88 | notificationsUI = notifies.map((not) => {
89 | if (not.type === "course")
90 | return (
91 |
92 | You are invited to a new course {not.name}.
93 |
94 |
101 |
102 |
105 |
106 |
107 | );
108 | else if (not.type === "exam") {
109 | return (
110 |
115 | );
116 | } else if (not.type === "result") {
117 | return (
118 |
123 | );
124 | }
125 | });
126 |
127 | if(notifies){
128 | return (notificationsUI)
129 | }
130 |
131 | return (Loading
)
132 | }
--------------------------------------------------------------------------------
/client/src/Components/PreviousExam/MarkSheet.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Container } from "react-bootstrap";
3 |
4 | import jsPDF from "jspdf";
5 | import html2canvas from "html2canvas";
6 |
7 | import MuiAlert from "@material-ui/lab/Alert";
8 | function Alert(props) {
9 | return ;
10 | }
11 |
12 | const MarkSheet = (props) => {
13 | const mcqExamsData = props.mcqExamsData;
14 | const cqExamsData = props.cqExamsData;
15 |
16 | let tableBody;
17 | let x = 1;
18 |
19 | const saveMarksheet = () => {
20 | html2canvas(document.querySelector("#resulttable")).then((canvas) => {
21 | // document.body.appendChild(canvas); // if you want see your screenshot in body.
22 | const imgData = canvas.toDataURL("image/png");
23 | const pdf = new jsPDF();
24 | pdf.addImage(imgData, "PNG", 0, 0);
25 | pdf.save("marksheet.pdf");
26 | });
27 | };
28 |
29 | if (mcqExamsData) {
30 | mcqExamsData.sort(function (a, b) {
31 | return b.mark - a.mark;
32 | });
33 |
34 | console.log("Exam Data", mcqExamsData);
35 |
36 | tableBody = mcqExamsData.map((data) => {
37 | console.log(data);
38 | return (
39 | <>
40 |
41 | {x++} |
42 |
43 |
44 | {x == 2 ? "👑" : ""}
45 |
46 | {`${data.student.firstName ? data.student.firstName : ""} ${
47 | data.student.lastName ? data.student.lastName : ""
48 | } ${data.student.username}`}
49 | |
50 | {data.student.registrationNo} |
51 |
52 |
53 | {data.student.email}
54 | |
55 | {data.solved} |
56 | {data.wrong} |
57 | {data.mark} |
58 | {data.windowChanged} |
59 |
60 | View
61 | |
62 |
63 | >
64 | );
65 | });
66 | } else if (cqExamsData) {
67 | cqExamsData.sort(function (a, b) {
68 | return b.totalMarks - a.totalMarks;
69 | });
70 |
71 | console.log("Exam Data", cqExamsData);
72 |
73 | tableBody = cqExamsData.map((data) => {
74 | console.log(data);
75 | return (
76 | <>
77 |
78 | {x++} |
79 |
80 |
81 | {x == 2 ? "👑" : ""}
82 |
83 | {`${data.student.firstName ? data.student.firstName : ""} ${
84 | data.student.lastName ? data.student.lastName : ""
85 | } ${data.student.username}`}
86 | |
87 | {data.student.registrationNo} |
88 |
89 |
90 | {data.student.email}
91 | |
92 | {data.totalMarks} |
93 | {data.wrong} |
94 | {data.totalMarks} |
95 | {data.windowChanged} |
96 |
97 | View
98 | |
99 |
100 | >
101 | );
102 | });
103 | }
104 |
105 | if (mcqExamsData || cqExamsData)
106 | return (
107 |
108 |
113 |
114 |
115 | # |
116 | Name |
117 | Registration No |
118 | Email |
119 | Solved |
120 | Wrong |
121 | Marks |
122 | Window Changed |
123 | Action |
124 |
125 |
126 |
127 | {tableBody}
128 |
129 |
137 |
138 | );
139 | else
140 | return (
141 |
142 |
143 |
No Participants
144 |
145 |
146 | );
147 | };
148 |
149 | export default MarkSheet;
150 |
--------------------------------------------------------------------------------
/client/src/Components/PreviousExam/PreviousExam.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: white;
3 | }
4 | .crown {
5 | animation: mymove 2s infinite;
6 | }
7 |
8 | @keyframes mymove {
9 | 100% {
10 | transform: rotate(360deg);
11 | }
12 | }
13 |
14 | .scroll-off{
15 | /* overflow-y: hidden; */
16 | }
17 |
18 | div.scroll {
19 | /* margin:4px, 4px; */
20 | /* padding:4px; */
21 | /* background-color: green; */
22 | /* width: 500px; */
23 | /* height: 110px; */
24 | /* overflow-x: hidden; */
25 | /* overflow: auto; */
26 | /* max-height: 100vh; */
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/Components/Profile/Profile.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Container from "react-bootstrap/Container";
3 | import Jumbotron from "react-bootstrap/Jumbotron";
4 | import { makeStyles } from "@material-ui/core/styles";
5 | import Row from "react-bootstrap/Row";
6 | import Col from "react-bootstrap/Col";
7 | import Forms from "../Generic/Forms";
8 | import Button from "@material-ui/core/Button";
9 | import SaveIcon from "@material-ui/icons/Save";
10 | import "./Profile.scss";
11 | import { LinearProgress } from "@material-ui/core";
12 |
13 | const useStyles = makeStyles((theme) => ({
14 | root: {
15 | display: "flex",
16 | flexWrap: "wrap",
17 | },
18 | margin: {
19 | // margin: theme.spacing(1),
20 | },
21 | textField: {
22 | // width: "15vw",
23 | // margin: theme.spacing(1),
24 | paddingRight: theme.spacing(1),
25 | marginTop: theme.spacing(2),
26 | },
27 | root: {
28 | width: "100%",
29 | "& > * + *": {
30 | marginTop: theme.spacing(2),
31 | },
32 | },
33 | shadows: ["none"],
34 | }));
35 |
36 | export default function Profile(props) {
37 | let userdata;
38 |
39 | useEffect(() => {
40 | userdata = localStorage.getItem("data");
41 | userdata = JSON.parse(userdata);
42 | // if (userdata) userdata = userdata;
43 | }, []);
44 |
45 | console.log(props.userInfo);
46 | const classes = useStyles();
47 |
48 | const [values, setValues] = useState({
49 | password: "",
50 | confirmPassword: "",
51 | firstName: "",
52 | lastName: "",
53 | error: "",
54 | });
55 | console.log(values.firstName);
56 | const handleChange = (prop) => (event) => {
57 | setValues({ ...values, [prop]: event.target.value });
58 | };
59 |
60 | if (props.userInfo)
61 | return (
62 |
63 |
64 |
65 |
66 |
67 | {props.userInfo.firstName + ' ' + props.userInfo.lastName}
68 | {props.userInfo.role}
69 |
70 |
71 |
72 |
73 | About
74 |
75 |
227 |
228 |
229 |
230 |
231 |
232 | );
233 | else return ;
234 | }
235 |
--------------------------------------------------------------------------------
/client/src/Components/Profile/Profile.scss:
--------------------------------------------------------------------------------
1 | .userName {
2 | margin: 2% 0 2% 0;
3 | padding: 5% 0% 5% 0%;
4 | background-color: white;
5 | }
6 | .about {
7 | margin: 2% 0 2% 0;
8 | padding-top: 2%;
9 | background-color: white;
10 | }
--------------------------------------------------------------------------------
/client/src/Components/Timer/Timer.css:
--------------------------------------------------------------------------------
1 | .timer-container {
2 | /* margin-top: 2%; */
3 | padding-top: 5%;
4 |
5 | display: flex;
6 | align-items: center;
7 | justify-content: center;
8 | font-family: 'Noto Serif', serif;
9 | }
10 |
11 | .timer-container ul {
12 | display: flex;
13 | list-style: none;
14 | margin: 0;
15 | padding: 0;
16 | }
17 |
18 | .timer-container ul li {
19 | background: #f6f8fa;
20 | border-radius: 2px;
21 | padding: 1rem;
22 | display: flex;
23 | flex-direction: column;
24 | margin: 0 0.5rem;
25 | box-shadow: 0px 0px 5px rgba(215, 235, 247, 0.5);
26 | }
27 |
28 | .timer-container ul li span {
29 | font-size: 2rem;
30 | }
31 | .enterExam {
32 | margin-top: 3.5%;
33 | }
34 | .enterHeading {
35 | margin-bottom: 1.5%;
36 | }
37 |
--------------------------------------------------------------------------------
/client/src/Components/Timer/Timer.js:
--------------------------------------------------------------------------------
1 | import { useRef, useState, useEffect } from "react";
2 | import { BrowserRouter as Router, Link } from "react-router-dom";
3 | import Container from "react-bootstrap/Container";
4 | import Row from "react-bootstrap/Row";
5 | import Col from "react-bootstrap/Col";
6 | import Button from '@material-ui/core/Button';
7 | import "./Timer.css";
8 |
9 | const Timer = (props) => {
10 | const [timerDays, setTimerDays] = useState("00");
11 | const [timerHours, setTimerHours] = useState("00");
12 | const [timerMinutes, setTimerMinutes] = useState("00");
13 | const [timerSeconds, setTimerSeconds] = useState("00");
14 |
15 | // console.log(props.deadline)
16 | let interval = useRef();
17 |
18 | const timer = (props) => {
19 | const seconds = 1000;
20 | const minutes = seconds * 60;
21 | const hours = minutes * 60;
22 | const days = hours * 24;
23 | const deadline = new Date(props.deadline).getTime();
24 |
25 | interval = setInterval(() => {
26 | const now = new Date().getTime();
27 | const timeLeft = deadline - now;
28 | if (timeLeft < 0) {
29 | clearInterval(interval.current);
30 | } else {
31 | setTimerDays(Math.floor(timeLeft / days));
32 | setTimerHours(Math.floor((timeLeft % days) / hours));
33 | setTimerMinutes(Math.floor((timeLeft % hours) / minutes));
34 | setTimerSeconds(Math.floor((timeLeft % minutes) / seconds));
35 | }
36 | }, 1000);
37 | };
38 |
39 | useEffect(() => {
40 | timer(props);
41 | return () => {
42 | clearInterval(interval.current);
43 | };
44 | });
45 |
46 | if (timerDays == 0 && timerHours == 0 && timerMinutes == 0 && timerSeconds == 0)
47 | return (
48 |
49 |
50 |
51 | Your Exam is Running!
52 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
65 | );
66 | else
67 | return (
68 |
69 |
70 | -
71 | {timerDays} Days
72 |
73 | -
74 | {timerHours} Hours
75 |
76 | -
77 | {timerMinutes} Minutes
78 |
79 | -
80 | {timerSeconds} Seconds
81 |
82 |
83 |
84 | );
85 | };
86 |
87 | export default Timer;
88 |
--------------------------------------------------------------------------------
/client/src/Components/UpcomingExam/UpcomingExam.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Timer from "../Timer/Timer";
3 | import { Col, Container, Row, Alert, Table } from "react-bootstrap";
4 | import { useParams } from "react-router-dom";
5 |
6 | const UpcomingExam = (props) => {
7 | var months = [
8 | "January",
9 | "February",
10 | "March",
11 | "April",
12 | "May",
13 | "June",
14 | "July",
15 | "August",
16 | "September",
17 | "October",
18 | "November",
19 | "December",
20 | ];
21 |
22 | var days = [
23 | "Sunday",
24 | "Monday",
25 | "Tuesday",
26 | "Wednesday",
27 | "Thursday",
28 | "Friday",
29 | "Saturday",
30 | ];
31 |
32 | const { id } = useParams();
33 |
34 | let userdata;
35 | userdata = localStorage.getItem("data");
36 | userdata = JSON.parse(userdata);
37 |
38 | let examInfo;
39 | if (userdata)
40 | userdata.courses.map((course) => {
41 | // console.log(course);
42 | course.course.cqExams.map((exam) => {
43 | // console.log(exam.examId._id);
44 | if (exam.examId._id == id) {
45 | // console.log(exam);
46 | examInfo = exam.examId;
47 | }
48 | });
49 | course.course.mcqExams.map((exam) => {
50 | // console.log(exam.examId._id);
51 | if (exam.examId._id == id) examInfo = exam.examId;
52 | });
53 | });
54 |
55 | console.log(examInfo);
56 |
57 | return (
58 |
59 |
60 | Exam Has Not Started Yet
61 |
62 | {/* */}
63 | {examInfo.name}
64 | {/* */}
65 |
66 |
67 |
68 |
69 |
70 |
78 |
79 |
80 | Time |
81 |
82 | {new Date(examInfo.date).getHours() < 10
83 | ? "0" + new Date(examInfo.date).getHours()
84 | : new Date(examInfo.date).getHours()}
85 | :
86 | {new Date(examInfo.date).getMinutes() < 10
87 | ? "0" + new Date(examInfo.date).getMinutes()
88 | : new Date(examInfo.date).getMinutes()}{" "}
89 | |
90 |
91 |
92 | Date |
93 |
94 | {new Date(examInfo.date).getDate()}th{" "}
95 | {months[new Date(examInfo.date).getMonth()]},
96 | {new Date(examInfo.date).getFullYear()} (
97 | {days[new Date(examInfo.date).getDay()]})
98 | |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
118 |
119 |
120 | Total Marks |
121 | {examInfo.totalMarks} |
122 |
123 |
124 | Total Time |
125 | {examInfo.totalTime} min |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 | );
136 | };
137 |
138 | export default UpcomingExam;
139 |
--------------------------------------------------------------------------------
/client/src/Containers/App.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
2 | @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@600&display=swap');
3 | @import url('https://fonts.googleapis.com/css2?family=Noto+Serif&display=swap');
4 |
5 | body {
6 | margin: 0;
7 | padding: 0;
8 | /* background-color: #F5F5F5; */
9 | background-color: #f6f8fa;
10 | }
--------------------------------------------------------------------------------
/client/src/Containers/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from "react";
2 | import { BrowserRouter, Route, Switch } from "react-router-dom";
3 | import "bootstrap/dist/css/bootstrap.min.css";
4 | import socketIOClient from "socket.io-client";
5 | import Navigation from "../Components/Navbar/Navbar";
6 | import SignIn from "../Components/Authentication/SignIn";
7 | import SignUp from "../Components/Authentication/SignUp";
8 | import Home from "../Components/Home/Home";
9 | import Profile from "../Components/Profile/Profile";
10 | import axios from "axios";
11 | import Layout from "../Components/Layout/Layout";
12 | import Course from "../Components/Course/Course";
13 | import Exam from "../Components/Exam/Exam";
14 | import LiveExam from "../Components/LiveExam/LiveExam";
15 | import PreviousExam from "../Components/PreviousExam/PreviousExam";
16 | import UpcomingExam from "../Components/UpcomingExam/UpcomingExam";
17 | import Examine from "../Components/PreviousExam/Examine";
18 | import Error404 from "../Components/404/Error404";
19 | import Notifications from "../Components/Notifications/Notification";
20 | import "./App.css";
21 |
22 | let userdata = localStorage.getItem("data");
23 | userdata = JSON.parse(userdata);
24 |
25 | function App() {
26 | const [loginStatus, setloginStatus] = useState(null);
27 |
28 | const [universityInfo, setUniversityInfo] = useState(null);
29 |
30 | const [userInfo, setUserInfo] = useState(null);
31 |
32 | const ENDPOINT = "http://127.0.0.1:8080/";
33 |
34 | const [notifications, setnotifications] = useState(null);
35 |
36 | let socketRef = useRef(null);
37 |
38 | useEffect(() => {
39 | if (userdata) {
40 | axios
41 | .get(`${userdata.role}/user/${userdata.id}`)
42 | .then((result) => {
43 | setloginStatus(result.data.status);
44 | setUserInfo(result.data.result.data);
45 | localStorage.setItem("data", JSON.stringify(result.data.result.data));
46 | console.log("UserInfo api call", result);
47 | })
48 | .catch((error) => {
49 | console.log(error);
50 | setloginStatus("Failed");
51 | console.log("Error api call", error);
52 | });
53 | } else setloginStatus("Failed");
54 | axios
55 | .get("/notifications")
56 | .then((result) => {
57 | console.log("Notifications ", result.data.result.data);
58 | setnotifications(result.data.result.data);
59 | })
60 | .catch((error) => {
61 | console.log(error);
62 | });
63 | axios
64 | .get("university/all")
65 | .then((response) => {
66 | const data = response.data;
67 |
68 | if (data.status === "OK") {
69 | setUniversityInfo(data.result.data.universities);
70 | }
71 | })
72 | .catch((error) => {
73 | console.log(error);
74 | });
75 | }, []);
76 |
77 | return (
78 |
79 |
80 |
85 |
86 |
87 | (
91 |
92 | )}
93 | />
94 |
95 | } />
96 | }
100 | />
101 |
102 |
103 |
104 | (
107 |
108 | )}
109 | />
110 |
111 | }
115 | />
116 |
117 | }
121 | />
122 | }
126 | />
127 | }
131 | />
132 |
133 |
134 |
135 |
136 |
137 | );
138 | }
139 |
140 | export default App;
141 |
--------------------------------------------------------------------------------
/client/src/Containers/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/client/src/hoc/Auxilary.js:
--------------------------------------------------------------------------------
1 | const Aux = props => props.children;
2 |
3 | export default Aux;
--------------------------------------------------------------------------------
/client/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./Containers/App";
5 | import reportWebVitals from "./reportWebVitals";
6 |
7 | import axios from "axios";
8 |
9 | let userdata = localStorage.getItem("data");
10 | userdata = JSON.parse(userdata);
11 | console.log(userdata);
12 |
13 | axios.defaults.baseURL = "http://localhost:8080/";
14 |
15 | if (userdata) {
16 | axios.defaults.headers.common["Authorization"] = "Token " + userdata.jwt.token;
17 | }
18 |
19 | ReactDOM.render(
20 |
21 |
22 | ,
23 | document.getElementById("root")
24 | );
25 |
26 | reportWebVitals();
27 |
--------------------------------------------------------------------------------
/client/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/client/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/database/courses:
--------------------------------------------------------------------------------
1 | [{
2 | "_id": {
3 | "$oid": "6010146ccf36944122caf45b"
4 | },
5 | "creationDate": {
6 | "$date": "2021-01-26T13:09:00.285Z"
7 | },
8 | "name": "Algebra",
9 | "code": "MAT101",
10 | "mcqExams": [],
11 | "cqExams": [],
12 | "__v": 0
13 | },{
14 | "_id": {
15 | "$oid": "60101499d9582841efe50144"
16 | },
17 | "creationDate": {
18 | "$date": "2021-01-26T13:09:37.847Z"
19 | },
20 | "name": "Algebra",
21 | "code": "MAT101",
22 | "mcqExams": [],
23 | "cqExams": [],
24 | "__v": 0
25 | },{
26 | "_id": {
27 | "$oid": "601014b539650242439115e3"
28 | },
29 | "creationDate": {
30 | "$date": "2021-01-26T13:10:10.930Z"
31 | },
32 | "name": "Algebra",
33 | "code": "MAT101",
34 | "mcqExams": [],
35 | "cqExams": [],
36 | "__v": 0
37 | },{
38 | "_id": {
39 | "$oid": "60101511032bbb43117d969e"
40 | },
41 | "creationDate": {
42 | "$date": "2021-01-26T13:11:41.183Z"
43 | },
44 | "name": "Algebra",
45 | "code": "MAT101",
46 | "mcqExams": [],
47 | "cqExams": [],
48 | "__v": 0
49 | },{
50 | "_id": {
51 | "$oid": "60101629eab66d4434084582"
52 | },
53 | "creationDate": {
54 | "$date": "2021-01-26T13:15:47.213Z"
55 | },
56 | "name": "Algebra",
57 | "code": "MAT101",
58 | "department": {
59 | "name": "CSE",
60 | "id": {
61 | "$oid": "600c75f1059f3d6697f4e93b"
62 | }
63 | },
64 | "varsity": {
65 | "name": "SUST",
66 | "id": {
67 | "$oid": "600c75f1059f3d6697f4e931"
68 | }
69 | },
70 | "mcqExams": [],
71 | "cqExams": [],
72 | "__v": 1,
73 | "students": [
74 | {
75 | "_id": {
76 | "$oid": "6015855a946f0c778c691c60"
77 | }
78 | }
79 | ]
80 | },{
81 | "_id": {
82 | "$oid": "60158e6e5e798487dd0d985f"
83 | },
84 | "creationDate": {
85 | "$date": "2021-01-30T16:43:28.590Z"
86 | },
87 | "name": "C Programming",
88 | "code": "SWE123",
89 | "department": {
90 | "id": {
91 | "$oid": "600c75f1059f3d6697f4e93a"
92 | },
93 | "name": "SWE"
94 | },
95 | "varsity": {
96 | "id": {
97 | "$oid": "600c75f1059f3d6697f4e931"
98 | },
99 | "name": "SUST"
100 | },
101 | "createdBy": {
102 | "$oid": "6015b154a411b8ce8c103c23"
103 | },
104 | "mcqExams": [
105 | {
106 | "_id": {
107 | "$oid": "6015ba8d5fb74ddde0a42ad5"
108 | },
109 | "examId": {
110 | "$oid": "6015ba8d5fb74ddde0a42ad1"
111 | }
112 | },
113 | {
114 | "_id": {
115 | "$oid": "6020aa8797970069088f5fe2"
116 | },
117 | "examId": {
118 | "$oid": "6020aa8797970069088f5fe0"
119 | }
120 | },
121 | {
122 | "_id": {
123 | "$oid": "6020ad9a97970069088f5ff2"
124 | },
125 | "examId": {
126 | "$oid": "6020ad9a97970069088f5fef"
127 | }
128 | },
129 | {
130 | "_id": {
131 | "$oid": "6020ae8897970069088f5ffb"
132 | },
133 | "examId": {
134 | "$oid": "6020ae8897970069088f5ff9"
135 | }
136 | },
137 | {
138 | "_id": {
139 | "$oid": "6020af5c97970069088f600b"
140 | },
141 | "examId": {
142 | "$oid": "6020af5c97970069088f6008"
143 | }
144 | },
145 | {
146 | "_id": {
147 | "$oid": "6020afc297970069088f6014"
148 | },
149 | "examId": {
150 | "$oid": "6020afc297970069088f6012"
151 | }
152 | },
153 | {
154 | "_id": {
155 | "$oid": "6020b03a97970069088f601d"
156 | },
157 | "examId": {
158 | "$oid": "6020b03a97970069088f601b"
159 | }
160 | },
161 | {
162 | "_id": {
163 | "$oid": "60214412c3d85719040ea72a"
164 | },
165 | "examId": {
166 | "$oid": "60214412c3d85719040ea726"
167 | }
168 | },
169 | {
170 | "_id": {
171 | "$oid": "6021448cc3d85719040ea733"
172 | },
173 | "examId": {
174 | "$oid": "6021448cc3d85719040ea731"
175 | }
176 | }
177 | ],
178 | "cqExams": [
179 | {
180 | "_id": {
181 | "$oid": "6015a30c98e7b7af0f4d0f47"
182 | },
183 | "examId": {
184 | "$oid": "6015bade5fb74ddde0a42ad6"
185 | }
186 | }
187 | ],
188 | "students": [
189 | {
190 | "_id": {
191 | "$oid": "6015855a946f0c778c691c60"
192 | },
193 | "student": "6015855a946f0c778c691c60"
194 | }
195 | ],
196 | "__v": 12
197 | },{
198 | "_id": {
199 | "$oid": "6015b2c55c6f3bcfe4c0d972"
200 | },
201 | "creationDate": {
202 | "$date": "2021-01-30T19:24:46.134Z"
203 | },
204 | "name": "C Programming",
205 | "code": "SWE123",
206 | "department": {
207 | "id": {
208 | "$oid": "600c75f1059f3d6697f4e93a"
209 | },
210 | "name": "SWE"
211 | },
212 | "varsity": {
213 | "id": {
214 | "$oid": "600c75f1059f3d6697f4e931"
215 | },
216 | "name": "SUST"
217 | },
218 | "createdBy": {
219 | "$oid": "6015b154a411b8ce8c103c23"
220 | },
221 | "mcqExams": [],
222 | "cqExams": [],
223 | "students": [],
224 | "__v": 0
225 | },{
226 | "_id": {
227 | "$oid": "6017d79c9f341b2d5f2893ad"
228 | },
229 | "creationDate": {
230 | "$date": "2021-02-01T10:27:33.100Z"
231 | },
232 | "name": "Node and Express Tutorial",
233 | "code": "SWE300",
234 | "department": {
235 | "id": {
236 | "$oid": "600c75f1059f3d6697f4e93a"
237 | },
238 | "name": "SWE"
239 | },
240 | "varsity": {
241 | "id": {
242 | "$oid": "600c75f1059f3d6697f4e931"
243 | },
244 | "name": "SUST"
245 | },
246 | "createdBy": {
247 | "$oid": "6015b154a411b8ce8c103c23"
248 | },
249 | "mcqExams": [],
250 | "cqExams": [],
251 | "students": [],
252 | "__v": 0
253 | }]
--------------------------------------------------------------------------------
/database/cqexams:
--------------------------------------------------------------------------------
1 | [{
2 | "_id": {
3 | "$oid": "6010364ee995357d92168583"
4 | },
5 | "course": {
6 | "$oid": "6010146ccf36944122caf45b"
7 | },
8 | "cqQuestions": [
9 | {
10 | "_id": {
11 | "$oid": "6010364ee995357d92168584"
12 | },
13 | "cqQuestionId": {
14 | "$oid": "6010343c75bad87bb49e3309"
15 | }
16 | },
17 | {
18 | "_id": {
19 | "$oid": "6010364ee995357d92168585"
20 | },
21 | "cqQuestionId": {
22 | "$oid": "6010345675bad87bb49e330a"
23 | }
24 | },
25 | {
26 | "_id": {
27 | "$oid": "6010364ee995357d92168586"
28 | },
29 | "cqQuestionId": {
30 | "$oid": "6010346975bad87bb49e330b"
31 | }
32 | }
33 | ],
34 | "totalTime": 60,
35 | "totalMarks": 100,
36 | "date": {
37 | "$date": "2016-11-12T09:00:00Z"
38 | },
39 | "__v": 0
40 | }]
--------------------------------------------------------------------------------
/database/cqquestions:
--------------------------------------------------------------------------------
1 | [{
2 | "_id": {
3 | "$oid": "6010343c75bad87bb49e3309"
4 | },
5 | "creationTime": {
6 | "$date": "2021-01-26T15:22:53.207Z"
7 | },
8 | "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled",
9 | "mainQuestion": "What is this?",
10 | "time": 120,
11 | "marks": 10,
12 | "__v": 0
13 | },{
14 | "_id": {
15 | "$oid": "6010345675bad87bb49e330a"
16 | },
17 | "creationTime": {
18 | "$date": "2021-01-26T15:22:53.207Z"
19 | },
20 | "mainQuestion": "Describe Your Life in words!",
21 | "time": 120,
22 | "marks": 10,
23 | "__v": 0
24 | },{
25 | "_id": {
26 | "$oid": "6010346975bad87bb49e330b"
27 | },
28 | "creationTime": {
29 | "$date": "2021-01-26T15:22:53.207Z"
30 | },
31 | "mainQuestion": "What is the differences between teacher and student?",
32 | "time": 120,
33 | "marks": 10,
34 | "__v": 0
35 | },{
36 | "_id": {
37 | "$oid": "6010356b75bad87bb49e330d"
38 | },
39 | "creationTime": {
40 | "$date": "2021-01-26T15:22:53.207Z"
41 | },
42 | "description": "Jokhon porbe na mor payer chinho ei pothe.Ami baibo na baibonago kheya tori ei ghat e.Jokhon porbe na mor payer chinho ei pothe.Ami baibo na baibonago kheya tori ei ghat eJokhon porbe na mor payer chinho ei pothe.Ami baibo na baibonago kheya tori ei ghat e",
43 | "mainQuestion": "sdasa sf asfas fsafasfasf ?",
44 | "time": 120,
45 | "marks": 10,
46 | "__v": 0
47 | }]
--------------------------------------------------------------------------------
/database/mcqexams:
--------------------------------------------------------------------------------
1 | [{
2 | "_id": {
3 | "$oid": "6015ba8d5fb74ddde0a42ad1"
4 | },
5 | "course": {
6 | "$oid": "60158e6e5e798487dd0d985f"
7 | },
8 | "name": "SX TT1",
9 | "mcqQuestions": [
10 | {
11 | "_id": {
12 | "$oid": "6015ba8d5fb74ddde0a42ad2"
13 | },
14 | "mcqQuestionId": {
15 | "$oid": "60101c05152a71544b170e8b"
16 | }
17 | },
18 | {
19 | "_id": {
20 | "$oid": "6015ba8d5fb74ddde0a42ad3"
21 | },
22 | "mcqQuestionId": {
23 | "$oid": "60101d7f0224a2573546d357"
24 | }
25 | },
26 | {
27 | "_id": {
28 | "$oid": "6015ba8d5fb74ddde0a42ad4"
29 | },
30 | "mcqQuestionId": {
31 | "$oid": "60101dd40224a2573546d35e"
32 | }
33 | }
34 | ],
35 | "totalTime": 30,
36 | "totalMarks": 100,
37 | "date": {
38 | "$date": "2021-02-07T14:13:48Z"
39 | },
40 | "__v": 0
41 | },{
42 | "_id": {
43 | "$oid": "6020a9fde9a9756220975cc8"
44 | },
45 | "course": {
46 | "$oid": "60158e6e5e798487dd0d985f"
47 | },
48 | "mcqQuestions": [
49 | {
50 | "_id": {
51 | "$oid": "6020a9fde9a9756220975cc9"
52 | },
53 | "mcqQuestionId": {
54 | "$oid": "6020a8e8e9a9756220975cc2"
55 | }
56 | }
57 | ],
58 | "totalTime": 60,
59 | "totalMarks": 21,
60 | "date": {
61 | "$date": "2021-05-19T04:30:00Z"
62 | },
63 | "name": "sasas",
64 | "__v": 0
65 | },{
66 | "_id": {
67 | "$oid": "6020aa8797970069088f5fe0"
68 | },
69 | "course": {
70 | "$oid": "60158e6e5e798487dd0d985f"
71 | },
72 | "mcqQuestions": [
73 | {
74 | "_id": {
75 | "$oid": "6020aa8797970069088f5fe1"
76 | },
77 | "mcqQuestionId": {
78 | "$oid": "6020a8e8e9a9756220975cc2"
79 | }
80 | }
81 | ],
82 | "totalTime": 60,
83 | "totalMarks": 21,
84 | "date": {
85 | "$date": "2021-05-19T04:30:00Z"
86 | },
87 | "name": "sasas",
88 | "__v": 0
89 | },{
90 | "_id": {
91 | "$oid": "6020ad9a97970069088f5fef"
92 | },
93 | "course": {
94 | "$oid": "60158e6e5e798487dd0d985f"
95 | },
96 | "mcqQuestions": [
97 | {
98 | "_id": {
99 | "$oid": "6020ad9a97970069088f5ff0"
100 | },
101 | "mcqQuestionId": {
102 | "$oid": "6020ad7f97970069088f5fe3"
103 | }
104 | },
105 | {
106 | "_id": {
107 | "$oid": "6020ad9a97970069088f5ff1"
108 | },
109 | "mcqQuestionId": {
110 | "$oid": "6020ad9097970069088f5fe9"
111 | }
112 | }
113 | ],
114 | "totalTime": 180,
115 | "totalMarks": 5,
116 | "date": {
117 | "$date": "2021-05-14T04:31:00Z"
118 | },
119 | "name": "WWWE",
120 | "__v": 0
121 | },{
122 | "_id": {
123 | "$oid": "6020ae8897970069088f5ff9"
124 | },
125 | "course": {
126 | "$oid": "60158e6e5e798487dd0d985f"
127 | },
128 | "mcqQuestions": [
129 | {
130 | "_id": {
131 | "$oid": "6020ae8897970069088f5ffa"
132 | },
133 | "mcqQuestionId": {
134 | "$oid": "6020ae7e97970069088f5ff3"
135 | }
136 | }
137 | ],
138 | "totalTime": 60,
139 | "totalMarks": 1,
140 | "date": {
141 | "$date": "2021-05-01T04:33:00Z"
142 | },
143 | "name": "ASDa",
144 | "__v": 0
145 | },{
146 | "_id": {
147 | "$oid": "6020af5c97970069088f6008"
148 | },
149 | "course": {
150 | "$oid": "60158e6e5e798487dd0d985f"
151 | },
152 | "mcqQuestions": [
153 | {
154 | "_id": {
155 | "$oid": "6020af5c97970069088f6009"
156 | },
157 | "mcqQuestionId": {
158 | "$oid": "6020af4597970069088f5ffc"
159 | }
160 | },
161 | {
162 | "_id": {
163 | "$oid": "6020af5c97970069088f600a"
164 | },
165 | "mcqQuestionId": {
166 | "$oid": "6020af5397970069088f6002"
167 | }
168 | }
169 | ],
170 | "totalTime": 660,
171 | "totalMarks": 124,
172 | "date": {
173 | "$date": "2021-05-14T04:30:00Z"
174 | },
175 | "name": "WWq",
176 | "__v": 0
177 | },{
178 | "_id": {
179 | "$oid": "6020afc297970069088f6012"
180 | },
181 | "course": {
182 | "$oid": "60158e6e5e798487dd0d985f"
183 | },
184 | "mcqQuestions": [
185 | {
186 | "_id": {
187 | "$oid": "6020afc297970069088f6013"
188 | },
189 | "mcqQuestionId": {
190 | "$oid": "6020afb597970069088f600c"
191 | }
192 | }
193 | ],
194 | "totalTime": 30,
195 | "totalMarks": 12,
196 | "date": {
197 | "$date": "2021-05-01T04:31:00Z"
198 | },
199 | "name": "BA",
200 | "__v": 0
201 | },{
202 | "_id": {
203 | "$oid": "6020b03a97970069088f601b"
204 | },
205 | "course": {
206 | "$oid": "60158e6e5e798487dd0d985f"
207 | },
208 | "mcqQuestions": [
209 | {
210 | "_id": {
211 | "$oid": "6020b03a97970069088f601c"
212 | },
213 | "mcqQuestionId": {
214 | "$oid": "6020b02f97970069088f6015"
215 | }
216 | }
217 | ],
218 | "totalTime": 120,
219 | "totalMarks": 1,
220 | "date": {
221 | "$date": "2021-05-01T04:32:00Z"
222 | },
223 | "name": "aaa",
224 | "__v": 0
225 | },{
226 | "_id": {
227 | "$oid": "60214412c3d85719040ea726"
228 | },
229 | "course": {
230 | "$oid": "60158e6e5e798487dd0d985f"
231 | },
232 | "mcqQuestions": [
233 | {
234 | "_id": {
235 | "$oid": "60214412c3d85719040ea727"
236 | },
237 | "mcqQuestionId": {
238 | "$oid": "6021439fc3d85719040ea710"
239 | }
240 | },
241 | {
242 | "_id": {
243 | "$oid": "60214412c3d85719040ea728"
244 | },
245 | "mcqQuestionId": {
246 | "$oid": "602143b6c3d85719040ea716"
247 | }
248 | },
249 | {
250 | "_id": {
251 | "$oid": "60214412c3d85719040ea729"
252 | },
253 | "mcqQuestionId": {
254 | "$oid": "602143e4c3d85719040ea71c"
255 | }
256 | }
257 | ],
258 | "totalTime": 4200,
259 | "totalMarks": 166,
260 | "date": {
261 | "$date": "2021-05-01T04:31:00Z"
262 | },
263 | "name": "Wt",
264 | "__v": 0
265 | },{
266 | "_id": {
267 | "$oid": "6021448cc3d85719040ea731"
268 | },
269 | "course": {
270 | "$oid": "60158e6e5e798487dd0d985f"
271 | },
272 | "mcqQuestions": [
273 | {
274 | "_id": {
275 | "$oid": "6021448cc3d85719040ea732"
276 | },
277 | "mcqQuestionId": {
278 | "$oid": "6021446fc3d85719040ea72b"
279 | }
280 | }
281 | ],
282 | "totalTime": 60,
283 | "totalMarks": 10,
284 | "date": {
285 | "$date": "2021-02-08T14:05:00Z"
286 | },
287 | "name": "sasas",
288 | "__v": 0
289 | }]
--------------------------------------------------------------------------------
/database/students:
--------------------------------------------------------------------------------
1 | [{
2 | "_id": {
3 | "$oid": "6015855a946f0c778c691c60"
4 | },
5 | "role": "Student",
6 | "email": "shifat@buet.edu",
7 | "username": "shifat",
8 | "password": "$2a$10$4bHW6tXtiDPvrxhGVj3CP.Uq4aL7VbhCFy3EyZceW9Ov3ePijQyyK",
9 | "firstName": "Shifat",
10 | "lastName": "Rahman",
11 | "department": {
12 | "$oid": "600eeb069c34055b3963adf7"
13 | },
14 | "registrationNo": 2017831051,
15 | "varsity": {
16 | "$oid": "600eeb069c34055b3963adee"
17 | },
18 | "session": "2017-2018",
19 | "courses": [
20 | {
21 | "_id": {
22 | "$oid": "6015abe55976cdc3c3cf866d"
23 | },
24 | "course": {
25 | "$oid": "60158e6e5e798487dd0d985f"
26 | }
27 | },
28 | {
29 | "_id": {
30 | "$oid": "602472700cc9c58e15802b63"
31 | },
32 | "course": {
33 | "$oid": "60246ab6b587a47bb823c1bd"
34 | }
35 | },
36 | {
37 | "_id": {
38 | "$oid": "602476f00cc9c58e15802b74"
39 | },
40 | "course": {
41 | "$oid": "602476e30cc9c58e15802b71"
42 | }
43 | },
44 | {
45 | "_id": {
46 | "$oid": "602476f00cc9c58e15802b75"
47 | },
48 | "course": {
49 | "$oid": "602476e30cc9c58e15802b71"
50 | }
51 | }
52 | ],
53 | "registered_at": {
54 | "$date": "2021-01-30T16:12:10.919Z"
55 | },
56 | "__v": 13,
57 | "notifications": []
58 | },{
59 | "_id": {
60 | "$oid": "6024c69fc241a95906880bd0"
61 | },
62 | "role": "Student",
63 | "email": "mehedi17@sust.edu",
64 | "username": "Shifat",
65 | "password": "$2a$10$1hNIRVwhOULxxNyr/jJ7WOQxMdH60RwlVuE6z2BGQhReXOlY8DkaW",
66 | "firstName": "",
67 | "lastName": "",
68 | "department": {
69 | "$oid": "600c75f1059f3d6697f4e93a"
70 | },
71 | "registrationNo": 21212121,
72 | "varsity": {
73 | "$oid": "600c75f1059f3d6697f4e931"
74 | },
75 | "session": "2017-2018",
76 | "courses": [],
77 | "notifications": [],
78 | "registered_at": {
79 | "$date": "2021-02-11T05:54:39.415Z"
80 | },
81 | "__v": 0
82 | }]
--------------------------------------------------------------------------------
/database/teachers:
--------------------------------------------------------------------------------
1 | [{
2 | "_id": {
3 | "$oid": "6015b154a411b8ce8c103c23"
4 | },
5 | "role": "Teacher",
6 | "email": "sania@@sust.edu",
7 | "username": "shifat",
8 | "password": "$2a$10$yjpavJYS7wl8zFv6GB6Teeh2nVHNnYVrcAh8IWk3JPgrClk1NFl2u",
9 | "firstName": "Mazah",
10 | "lastName": "Kafi",
11 | "department": {
12 | "$oid": "600c75f1059f3d6697f4e93a"
13 | },
14 | "varsity": {
15 | "$oid": "600c75f1059f3d6697f4e931"
16 | },
17 | "designation": "Professor",
18 | "courses": [
19 | {
20 | "_id": {
21 | "$oid": "6017d79c9f341b2d5f2893ae"
22 | },
23 | "course": {
24 | "$oid": "60158e6e5e798487dd0d985f"
25 | }
26 | },
27 | {
28 | "_id": {
29 | "$oid": "6022b68c23203f6741545e50"
30 | },
31 | "course": {
32 | "$oid": "6022ce03cf2a4ca29524fa1a"
33 | }
34 | },
35 | {
36 | "_id": {
37 | "$oid": "6023ad138aa1303f6ab41139"
38 | },
39 | "course": {
40 | "$oid": "6023ad128aa1303f6ab41138"
41 | }
42 | },
43 | {
44 | "_id": {
45 | "$oid": "6023ae618aa1303f6ab4113b"
46 | },
47 | "course": {
48 | "$oid": "6023ae608aa1303f6ab4113a"
49 | }
50 | },
51 | {
52 | "_id": {
53 | "$oid": "6024288f5a6220390669fc79"
54 | },
55 | "course": {
56 | "$oid": "6024288e5a6220390669fc78"
57 | }
58 | },
59 | {
60 | "_id": {
61 | "$oid": "60242b135a6220390669fc7b"
62 | },
63 | "course": {
64 | "$oid": "60242b125a6220390669fc7a"
65 | }
66 | },
67 | {
68 | "_id": {
69 | "$oid": "60242c85c74c613d39bbebd8"
70 | },
71 | "course": {
72 | "$oid": "60242c84c74c613d39bbebd7"
73 | }
74 | },
75 | {
76 | "_id": {
77 | "$oid": "60242e5afbcda8406732ff49"
78 | },
79 | "course": {
80 | "$oid": "60242e58fbcda8406732ff48"
81 | }
82 | },
83 | {
84 | "_id": {
85 | "$oid": "60242efefbcda8406732ff4b"
86 | },
87 | "course": {
88 | "$oid": "60242efdfbcda8406732ff4a"
89 | }
90 | },
91 | {
92 | "_id": {
93 | "$oid": "60242f4efbcda8406732ff4d"
94 | },
95 | "course": {
96 | "$oid": "60242f4cfbcda8406732ff4c"
97 | }
98 | },
99 | {
100 | "_id": {
101 | "$oid": "6024587e443a296dac35f46c"
102 | },
103 | "course": {
104 | "$oid": "6024587d443a296dac35f46a"
105 | }
106 | },
107 | {
108 | "_id": {
109 | "$oid": "602459d4608994710a0bdfda"
110 | },
111 | "course": {
112 | "$oid": "602459d3608994710a0bdfd8"
113 | }
114 | },
115 | {
116 | "_id": {
117 | "$oid": "60245afe608994710a0bdfee"
118 | },
119 | "course": {
120 | "$oid": "60245afd608994710a0bdfec"
121 | }
122 | },
123 | {
124 | "_id": {
125 | "$oid": "60245bf7608994710a0bdff1"
126 | },
127 | "course": {
128 | "$oid": "60245bf6608994710a0bdfef"
129 | }
130 | },
131 | {
132 | "_id": {
133 | "$oid": "60246ab7b587a47bb823c1bf"
134 | },
135 | "course": {
136 | "$oid": "60246ab6b587a47bb823c1bd"
137 | }
138 | },
139 | {
140 | "_id": {
141 | "$oid": "602476e40cc9c58e15802b73"
142 | },
143 | "course": {
144 | "$oid": "602476e30cc9c58e15802b71"
145 | }
146 | }
147 | ],
148 | "registered_at": {
149 | "$date": "2021-01-30T19:19:48.333Z"
150 | },
151 | "__v": 37
152 | },{
153 | "_id": {
154 | "$oid": "6024c7c591a2205fce6b7934"
155 | },
156 | "role": "Teacher",
157 | "email": "mehedi17@sust.edu",
158 | "username": "shifatx",
159 | "password": "$2a$10$o4HwIut8qcTLF4mi0urexu00y4DCx762uq/4A8yNAVTbqG3n1VRG6",
160 | "firstName": "Hasan",
161 | "lastName": "Mh",
162 | "department": {
163 | "$oid": "600c75f1059f3d6697f4e93a"
164 | },
165 | "varsity": {
166 | "$oid": "600c75f1059f3d6697f4e931"
167 | },
168 | "designation": "Professor",
169 | "courses": [],
170 | "registered_at": {
171 | "$date": "2021-02-11T05:59:33.096Z"
172 | },
173 | "__v": 0
174 | }]
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "requires": true,
3 | "lockfileVersion": 1,
4 | "dependencies": {
5 | "base64-arraybuffer": {
6 | "version": "0.2.0",
7 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
8 | "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ=="
9 | },
10 | "css-line-break": {
11 | "version": "1.1.1",
12 | "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.1.1.tgz",
13 | "integrity": "sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==",
14 | "requires": {
15 | "base64-arraybuffer": "^0.2.0"
16 | }
17 | },
18 | "html2canvas": {
19 | "version": "1.0.0-rc.7",
20 | "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-rc.7.tgz",
21 | "integrity": "sha512-yvPNZGejB2KOyKleZspjK/NruXVQuowu8NnV2HYG7gW7ytzl+umffbtUI62v2dCHQLDdsK6HIDtyJZ0W3neerA==",
22 | "requires": {
23 | "css-line-break": "1.1.1"
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/server/.env:
--------------------------------------------------------------------------------
1 | MONGO_URL = mongodb+srv://test:test123@cluster0.xu3te.mongodb.net/vtest?retryWrites=true&w=majority
2 |
3 | MONGO_URL_o = mongodb://localhost:27017
4 |
5 | JWT_SECRET_TOKEN = SHITAPI
6 | SERVER_HOST = localhost
7 | SERVER_PORT = 8080
8 | JWT_EXPIRES_IN = 24h
9 |
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # # Created by https://www.toptal.com/developers/gitignore/api/node
3 | # # Edit at https://www.toptal.com/developers/gitignore?templates=node
4 |
5 | # ### Node ###
6 | # # Logs
7 | # logs
8 | # *.log
9 | # npm-debug.log*
10 | # yarn-debug.log*
11 | # yarn-error.log*
12 | # lerna-debug.log*
13 |
14 | # # Diagnostic reports (https://nodejs.org/api/report.html)
15 | # report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
16 |
17 | # # Runtime data
18 | # pids
19 | # *.pid
20 | # *.seed
21 | # *.pid.lock
22 |
23 | # # Directory for instrumented libs generated by jscoverage/JSCover
24 | # lib-cov
25 |
26 | # # Coverage directory used by tools like istanbul
27 | # coverage
28 | # *.lcov
29 |
30 | # # nyc test coverage
31 | # .nyc_output
32 |
33 | # # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
34 | # .grunt
35 |
36 | # # Bower dependency directory (https://bower.io/)
37 | # bower_components
38 |
39 | # # node-waf configuration
40 | # .lock-wscript
41 |
42 | # # Compiled binary addons (https://nodejs.org/api/addons.html)
43 | # build/Release
44 |
45 | # # Dependency directories
46 | node_modules/
47 | # jspm_packages/
48 |
49 | # # TypeScript v1 declaration files
50 | # typings/
51 |
52 | # # TypeScript cache
53 | # *.tsbuildinfo
54 |
55 | # # Optional npm cache directory
56 | # .npm
57 |
58 | # # Optional eslint cache
59 | # .eslintcache
60 |
61 | # # Microbundle cache
62 | # .rpt2_cache/
63 | # .rts2_cache_cjs/
64 | # .rts2_cache_es/
65 | # .rts2_cache_umd/
66 |
67 | # # Optional REPL history
68 | # .node_repl_history
69 |
70 | # # Output of 'npm pack'
71 | # *.tgz
72 |
73 | # # Yarn Integrity file
74 | # .yarn-integrity
75 |
76 | # # dotenv environment variables file
77 | # .env
78 | # .env.test
79 | # .env*.local
80 |
81 | # # parcel-bundler cache (https://parceljs.org/)
82 | # .cache
83 | # .parcel-cache
84 |
85 | # # Next.js build output
86 | # .next
87 |
88 | # # Nuxt.js build / generate output
89 | # .nuxt
90 | # dist
91 |
92 | # # Gatsby files
93 | # .cache/
94 | # # Comment in the public line in if your project uses Gatsby and not Next.js
95 | # # https://nextjs.org/blog/next-9-1#public-directory-support
96 | # # public
97 |
98 | # # vuepress build output
99 | # .vuepress/dist
100 |
101 | # # Serverless directories
102 | # .serverless/
103 |
104 | # # FuseBox cache
105 | # .fusebox/
106 |
107 | # # DynamoDB Local files
108 | # .dynamodb/
109 |
110 | # # TernJS port file
111 | # .tern-port
112 |
113 | # # Stores VSCode versions used for testing VSCode extensions
114 | # .vscode-test
115 |
116 | # # End of https://www.toptal.com/developers/gitignore/api/node
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const bodyParser = require("body-parser");
3 | const cors = require("cors");
4 | const helmet = require("helmet");
5 | const xssClean = require("xss-clean");
6 | const compression = require("compression");
7 |
8 | const socketIO = require("socket.io");
9 |
10 | const router = require("./routes");
11 |
12 | const app = express();
13 |
14 | app.use(cors());
15 | app.use(helmet());
16 | app.use(compression());
17 | app.use(xssClean());
18 |
19 | app.use((req, res, next) => {
20 | res.header("Access-Control-Allow-Origin", "*");
21 | res.header(
22 | "Access-Control-Allow-Headers",
23 | "Authorization, X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Allow-Request-Method"
24 | );
25 | res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
26 | res.header("Allow", "GET, POST, OPTIONS, PUT, DELETE");
27 | next();
28 | });
29 |
30 | app.set("view engine", "ejs");
31 |
32 | app.set("view", "view");
33 |
34 |
35 |
36 | app.use(bodyParser.json());
37 |
38 | app.use(
39 | bodyParser.urlencoded({
40 | extended: false,
41 | })
42 | );
43 |
44 | app.get("/", (req, res, next) => {
45 | res.status(202).send("Hello");
46 | next();
47 | });
48 |
49 | app.use(router);
50 |
51 | module.exports = app;
52 |
--------------------------------------------------------------------------------
/server/controllers/error.js:
--------------------------------------------------------------------------------
1 | exports.get404 = (req, res, next) => {
2 | res.status(404).send('Page Not Found');
3 | };
4 |
--------------------------------------------------------------------------------
/server/controllers/exam.js:
--------------------------------------------------------------------------------
1 | const UniversityModel = require("../models/university");
2 | const StudentModel = require("../models/student");
3 | const TeacherModel = require("../models/teacher");
4 | const CourseModel = require("../models/course");
5 | const McqQuestionModel = require("../models/mcqQuestion");
6 | const McqExamModel = require("../models/mcqExam");
7 | const CqQuestionModel = require("../models/cqQuestion");
8 | const CqExamModel = require("../models/cqExam");
9 |
10 | let interval;
11 |
12 | const examController = (io) => {
13 | io.on("connection", (socket) => {
14 |
15 | // console.log("New client Connected!");
16 | // const ip = socket.handshake.headers || socket.conn.remoteAddress;
17 | // console.log(ip);
18 | // console.log("Socket ID : ", socket.id);
19 | // let interval;
20 |
21 | // if (interval) clearInterval(interval);
22 |
23 | // interval = setInterval(() => getApiAndEmit(socket), 1000);
24 |
25 | // interval = setInterval(() => {
26 | // const response = new Date();
27 | // io.emit("test", response.getSeconds());
28 | // }, 1000);
29 |
30 | // let exams = [];
31 |
32 | // McqExamModel.find()
33 | // .then((result) => {
34 | // // console.log(result);
35 |
36 | // result.forEach((element) => {
37 | // exams.push(element);
38 | // });
39 |
40 | // setInterval(() => {
41 | // const date = new Date();
42 | // console.log(date.getTime(), exams[0].date.getTime());
43 |
44 | // if (exams[0].date.getHours() == date.getHours() ) {
45 | // console.log("HE");
46 | // }
47 | // }, 500);
48 |
49 | // io.emit("exam", exams);
50 | // })
51 | // .catch((error) => {
52 | // console.log(error);
53 | // });
54 |
55 | socket.on("disconnect", (reason) => {
56 | console.log("Client Disconnected!");
57 | console.log("Reason", reason);
58 | clearInterval(interval);
59 | });
60 | });
61 | };
62 |
63 | module.exports = examController;
64 |
--------------------------------------------------------------------------------
/server/controllers/notification.js:
--------------------------------------------------------------------------------
1 | const CourseModel = require("../models/course");
2 | const McqExamModel = require("../models/mcqExam");
3 | const CqExamModel = require("../models/cqExam");
4 |
5 | let interval;
6 |
7 | const notificationController = (io) => {
8 | io.on("connection", (socket) => {
9 | CourseModel.watch().on("change", (data) => {
10 | console.log(data);
11 | io.emit("notification", data);
12 | });
13 | });
14 |
15 | // io.on("connection", (socket) => {
16 | // console.log("New client Connected!");
17 | // const ip = socket.handshake.headers || socket.conn.remoteAddress;
18 | // console.log(ip);
19 | // console.log("Socket ID : ", socket.id);
20 |
21 | // if (interval) clearInterval(interval);
22 |
23 | // // interval = setInterval(() => getApiAndEmit(socket), 1000);
24 |
25 | // interval = setInterval(() => {
26 | // const response = new Date();
27 | // io.emit("test", response.getSeconds());
28 | // }, 1000);
29 |
30 | // let exams =[] ;
31 |
32 | // McqExamModel.find()
33 | // .then((result) => {
34 | // console.log(result);
35 |
36 | // result.forEach(element => {
37 |
38 | // exams.push(element);
39 |
40 | // });
41 |
42 | // })
43 | // .catch((error) => {
44 | // console.log(error);
45 | // });
46 |
47 | // socket.on("disconnect", (reason) => {
48 | // console.log("Client Disconnected!");
49 | // console.log("Reason", reason);
50 | // clearInterval(interval);
51 | // });
52 | // });
53 | };
54 |
55 | module.exports = notificationController;
56 |
--------------------------------------------------------------------------------
/server/controllers/university.js:
--------------------------------------------------------------------------------
1 | const UniversityModel = require("../models/university");
2 |
3 | exports.getUniversities = (req, res, next) => {
4 | UniversityModel.find()
5 | .then((universities) => {
6 | universities.password = undefined;
7 |
8 | return res.status(201).json({
9 | status: "OK",
10 | result: {
11 | data: {
12 | universities,
13 | },
14 | },
15 | });
16 | })
17 | .catch((error) => {
18 | console.log(error);
19 | });
20 | };
21 |
--------------------------------------------------------------------------------
/server/middleware/apiResponseInJson.js:
--------------------------------------------------------------------------------
1 |
2 | const apiResponseInJson = (res, statusCode, response) => {
3 | return res.status(statusCode).json({
4 | status: "OK",
5 | result: {
6 | data: response,
7 | },
8 | });
9 | };
10 |
11 | module.exports = apiResponseInJson;
12 |
--------------------------------------------------------------------------------
/server/middleware/authenticateJWS.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 | const jwt = require("jsonwebtoken");
3 |
4 | const StudentModel = require("../models/student");
5 | const TeacherModel = require("../models/teacher");
6 | const errorHandler = require("./errorHandler");
7 |
8 | module.exports = function (req, res, next) {
9 | const authHeader = req.headers.authorization;
10 |
11 | if (authHeader) {
12 | const token = authHeader.split(" ")[1];
13 |
14 | jwt.verify(token, process.env.JWT_SECRET_TOKEN, (err, user) => {
15 | if (err) {
16 | errorHandler.unauthorizedAccess(res);
17 | // return res.status(403).json({
18 | // status: "FAILED",
19 | // comment: "Invalid token"
20 | // });
21 | } else {
22 | console.log("Verified token");
23 |
24 | // console.log(user);
25 |
26 | console.log(new Date(user.iat * 1000));
27 |
28 | // console.log(user._id);
29 |
30 | StudentModel.findById(user._id)
31 | .then((student) => {
32 | if (student) {
33 | req.user = student;
34 | next();
35 | } else {
36 | console.log("User not found! in Student DB");
37 |
38 | TeacherModel.findById(user._id).then((teacher) => {
39 | if (teacher) {
40 | req.user = teacher;
41 | console.log(teacher);
42 | next();
43 | } else {
44 | console.log("User not found! in Teacher DB");
45 | errorHandler.unauthorizedAccess(res);
46 | }
47 | });
48 | }
49 | })
50 | .catch((error) => console.log(error));
51 | }
52 | });
53 | } else {
54 | errorHandler.unauthorizedAccess(res);
55 | // res.status(401).json({
56 | // status: "FAILED",
57 | // comment: "No token given.."
58 | // });
59 | }
60 | };
61 |
--------------------------------------------------------------------------------
/server/middleware/errorHandler.js:
--------------------------------------------------------------------------------
1 | exports.serverError = (res) => {
2 | // function serverError() {
3 | return res.status(500).json({
4 | status: "FAILED",
5 | result: "Something went wrong in server.",
6 | });
7 | // };
8 | };
9 |
10 | exports.unauthorizedAccess = (res) => {
11 | return res.status(401).json({
12 | status: "FAILED",
13 | result: "Unauthorized access",
14 | });
15 | };
16 |
17 | exports.unauthorizedEmail = (res) => {
18 | return res.status(401).json({
19 | status: "FAILED",
20 | result: "Unauthorized email address",
21 | });
22 | };
23 |
24 | exports.validationError = (res, statusCode, errorMessage) => {
25 | return res.status(statusCode).json({
26 | status: "FAILED",
27 | result: errorMessage,
28 | });
29 | };
30 |
--------------------------------------------------------------------------------
/server/middleware/restrictUser.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspw/Paper/164d8740bee4e561072c68c47d13524f962a1b67/server/middleware/restrictUser.js
--------------------------------------------------------------------------------
/server/models/course.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const autopopulate = require("mongoose-autopopulate");
3 |
4 | const Schema = mongoose.Schema;
5 |
6 | const courseSchema = new Schema({
7 | name: {
8 | type: String,
9 | required: true,
10 | unique: false,
11 | },
12 |
13 | code: {
14 | type: String,
15 | required: true,
16 | unique: false,
17 | },
18 |
19 | department: {
20 | id: {
21 | type: Schema.Types.ObjectId,
22 | ref: "University.departments",
23 | required: true,
24 | },
25 | name: {
26 | type: String,
27 | required: true,
28 | },
29 | },
30 | varsity: {
31 | name: {
32 | type: String,
33 | required: true,
34 | },
35 | id: {
36 | type: Schema.Types.ObjectId,
37 | ref: "University",
38 | required: true,
39 | },
40 | },
41 |
42 | mcqExams: [
43 | {
44 | examId: {
45 | type: Schema.Types.ObjectId,
46 | ref: "McqExam",
47 |
48 | autopopulate: { maxDepth: 3 }
49 | // required: true,
50 | },
51 | },
52 | ],
53 |
54 | cqExams: [
55 | {
56 | examId: {
57 | type: Schema.Types.ObjectId,
58 | ref: "CqExam",
59 | // required: true,
60 | autopopulate: { maxDepth: 3 }
61 | },
62 | },
63 | ],
64 |
65 | students: [
66 | {
67 | studentDetail: {
68 | type: Schema.Types.ObjectId,
69 | ref: "Student",
70 | autopopulate: { maxDepth: 3 },
71 | // required: true,
72 | },
73 | },
74 | ],
75 |
76 | createdBy: {
77 | type: Schema.Types.ObjectId,
78 | ref: "Teacher",
79 | autopopulate: { maxDepth: 2 },
80 | required: true,
81 | },
82 |
83 | creationDate: {
84 | type: Date,
85 | default: Date.now(),
86 | },
87 | });
88 | courseSchema.plugin(require("mongoose-autopopulate"));
89 | module.exports = mongoose.model("Course", courseSchema);
90 |
--------------------------------------------------------------------------------
/server/models/cqExam.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | // const autopopulate = require("mongoose-autopopulate");
3 | const Schema = mongoose.Schema;
4 |
5 | const cqExamSchema = new Schema({
6 | course: {
7 | type: Schema.Types.ObjectId,
8 | ref: "Course",
9 | required: true,
10 | autopopulate: { maxDepth: 1 },
11 | },
12 | name: {
13 | type: String,
14 | required: true,
15 | },
16 | cqQuestions: [
17 | {
18 | cqQuestionId: {
19 | type: Schema.Types.ObjectId,
20 | ref: "CqQuestion",
21 | required: true,
22 | autopopulate: { maxDepth: 2 },
23 | },
24 | },
25 | ],
26 | totalTime: {
27 | type: Number,
28 | required: true,
29 | },
30 | totalMarks: {
31 | type: Number,
32 | required: true,
33 | },
34 | date: {
35 | type: Date,
36 | required: true,
37 | },
38 | // createdBy: {
39 | // type: Schema.Types.ObjectId,
40 | // ref: "Teacher",
41 | // required: true,
42 | // autopopulate: { maxDepth: 1 },
43 | // },
44 | });
45 | cqExamSchema.plugin(require("mongoose-autopopulate"));
46 | module.exports = mongoose.model("CqExam", cqExamSchema);
47 |
--------------------------------------------------------------------------------
/server/models/cqExamine.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const cqExamine = new Schema({
6 | onCqExams: {
7 | type: Schema.Types.ObjectId,
8 | ref: "OnCqExam",
9 | required:true
10 | },
11 |
12 | });
13 | cqExamine.plugin(require('mongoose-autopopulate'));
14 | module.exports = mongoose.model("CqExamine", cqExamine);
15 |
--------------------------------------------------------------------------------
/server/models/cqQuestion.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const cqQuestionSchema = new Schema({
6 |
7 | description: {
8 | type: String,
9 | },
10 | descriptionImage: {
11 | type: Schema.Types.Buffer,
12 | },
13 | mainQuestion: {
14 | type: String,
15 | required:true
16 | },
17 | time: {
18 | type: Number,
19 | required:true
20 | },
21 | marks: {
22 | type: Number,
23 | },
24 | creationTime: {
25 | type: Date,
26 | default: Date.now(),
27 | },
28 | });
29 | cqQuestionSchema.plugin(require('mongoose-autopopulate'));
30 | module.exports = mongoose.model("CqQuestion", cqQuestionSchema);
31 |
--------------------------------------------------------------------------------
/server/models/mcqExam.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const mcqExamSchema = new Schema({
6 | course: {
7 | type: Schema.Types.ObjectId,
8 | ref: "Course",
9 | required:true,
10 | autopopulate: { maxDepth: 1 },
11 | },
12 | name: {
13 | type: String,
14 | required: true,
15 | },
16 | mcqQuestions: [
17 | {
18 | mcqQuestionId: {
19 | type: Schema.Types.ObjectId,
20 | ref: "McqQuestion",
21 | required: true,
22 | autopopulate: { maxDepth: 2 },
23 | },
24 | },
25 | ],
26 | totalTime: {
27 | type: Number,
28 | required: true,
29 | },
30 | totalMarks: {
31 | type: Number,
32 | required: true,
33 | },
34 | date: {
35 | type: Date,
36 | required:true
37 | },
38 | // createdBy : {
39 | // type: Schema.Types.ObjectId,
40 | // ref: "Teacher",
41 | // required: true,
42 | // autopopulate: { maxDepth: 1 },
43 | // }
44 | });
45 | mcqExamSchema.plugin(require('mongoose-autopopulate'));
46 | module.exports = mongoose.model("McqExam", mcqExamSchema);
47 |
--------------------------------------------------------------------------------
/server/models/mcqQuestion.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const mcqQuestionSchema = new Schema({
6 | description: {
7 | type: String,
8 | },
9 | descriptionImage: {
10 | type: Schema.Types.Buffer,
11 | },
12 | mainQuestion: {
13 | type: String,
14 | required: true,
15 | },
16 | options: [
17 | {
18 | option: String,
19 | // required: true,
20 | },
21 | ],
22 | correctAnswers: [
23 | {
24 | answer: String,
25 | },
26 | ],
27 | time: {
28 | type: Number,
29 | required: true,
30 | },
31 |
32 | marks: {
33 | type: Number,
34 | required: true,
35 | },
36 | });
37 | mcqQuestionSchema.plugin(require("mongoose-autopopulate"));
38 | module.exports = mongoose.model("McqQuestion", mcqQuestionSchema);
39 |
--------------------------------------------------------------------------------
/server/models/notification.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const autopopulate = require("mongoose-autopopulate");
3 |
4 | const Schema = mongoose.Schema;
5 |
6 | const notificationSchema = new Schema({
7 | type: {
8 | type: String,
9 | },
10 | typeID: {
11 | type: Schema.Types.ObjectId,
12 | },
13 | name :{
14 | type: String,
15 | },
16 | varsity: {
17 | type: String,
18 | },
19 | department: {
20 | type: String,
21 | },
22 | });
23 |
24 | notificationSchema.plugin(require("mongoose-autopopulate"));
25 | module.exports = mongoose.model("Notification", notificationSchema);
26 |
--------------------------------------------------------------------------------
/server/models/onCqExam.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const onCqExamSchema = new Schema({
6 | cqExam: {
7 | type: Schema.Types.ObjectId,
8 | ref: "CqExam",
9 | autopopulate: { maxDepth: 2 },
10 | },
11 | student: {
12 | type: Schema.Types.ObjectId,
13 | ref: "Student",
14 | autopopulate: { maxDepth: 2 },
15 | },
16 | studentAnswers: [
17 | {
18 | cqQuestion: {
19 | type: Schema.Types.ObjectId,
20 | ref: "CqQuestion",
21 | autopopulate: { maxDepth: 2 },
22 | },
23 | studentAnswer: {
24 | type: String,
25 | },
26 | },
27 | ],
28 | submitOn: {
29 | type: Date,
30 | default: Date.now,
31 | },
32 | marks: [
33 | {
34 | cqQuestion: {
35 | type: Schema.Types.ObjectId,
36 | ref: "CqQuestion",
37 | autopopulate: { maxDepth: 1 },
38 | },
39 | mark: {
40 | type: Number,
41 | },
42 | },
43 | ],
44 | totalMarks: {
45 | type: Number,
46 | },
47 | feedback: {
48 | type: String,
49 | },
50 | windowChanged: {
51 | type: Number,
52 | },
53 | examineBy: {
54 | type: Schema.Types.ObjectId,
55 | ref: "Teacher",
56 | autopopulate: { maxDepth: 1 },
57 | },
58 | });
59 | onCqExamSchema.plugin(require("mongoose-autopopulate"));
60 | onCqExamSchema.index({ cqExam: 1, student: 1 }, { unique: true });
61 | module.exports = mongoose.model("OnCqExam", onCqExamSchema);
62 |
--------------------------------------------------------------------------------
/server/models/onMcqExam.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const onMcqExamSchema = new Schema({
6 | mcqExam: {
7 | type: Schema.Types.ObjectId,
8 | ref: "McqExam",
9 | required: true,
10 | autopopulate: { maxDepth: 2 },
11 | },
12 | student: {
13 | type: Schema.Types.ObjectId,
14 | ref: "Student",
15 | required: true,
16 | autopopulate: { maxDepth: 2 },
17 | },
18 | studentAnswers: [
19 | {
20 | mcqQuestion: {
21 | type: Schema.Types.ObjectId,
22 | ref: "McqQuestion",
23 | required: true,
24 | autopopulate: { maxDepth: 2 },
25 | },
26 | studentAnswer: {
27 | type: String,
28 | },
29 | },
30 | ],
31 | solved: {
32 | type: Number,
33 | required: true,
34 | },
35 | wrong: {
36 | type: Number,
37 | required: true,
38 | },
39 | mark: {
40 | type: Number,
41 | required: true,
42 | },
43 | feedback:{
44 | type : String
45 | },
46 | windowChanged: {
47 | type: Number,
48 | },
49 | submitOn: {
50 | type: Date,
51 | default: Date.now,
52 | },
53 | });
54 | onMcqExamSchema.plugin(require("mongoose-autopopulate"));
55 | onMcqExamSchema.index({ mcqExam: 1, student: 1 }, { unique: true });
56 | module.exports = mongoose.model("OnMcqExam", onMcqExamSchema);
57 |
--------------------------------------------------------------------------------
/server/models/student.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const validator = require("validator");
3 | // const autopopulate = require('mongoose-autopopulate')
4 |
5 | const Schema = mongoose.Schema;
6 |
7 | const studentSchema = new Schema({
8 | role: {
9 | type: String,
10 | required: true,
11 | enum: ["Student", "Teacher"],
12 | },
13 | username: {
14 | type: String,
15 | require: true,
16 | unique: true,
17 | minlength: 3,
18 | },
19 |
20 | email: {
21 | type: String,
22 | unique: true,
23 | lowercase: true,
24 | unique: true,
25 | },
26 | password: {
27 | type: String,
28 | required: [true, "Please enter a password"],
29 | },
30 | firstName: {
31 | type: String,
32 | },
33 | lastName: {
34 | type: String,
35 | },
36 | department: {
37 | type: Schema.Types.ObjectId,
38 | ref: "University.departments",
39 | required: true,
40 | },
41 | varsity: {
42 | type: Schema.Types.ObjectId,
43 | ref: "University",
44 | required: true,
45 | autopopulate: { maxDepth: 2 },
46 | },
47 | registrationNo: {
48 | type: Number,
49 | required: true,
50 | },
51 | session: {
52 | type: String,
53 | required: true,
54 | },
55 | courses: [
56 | {
57 | course: {
58 | type: Schema.Types.ObjectId,
59 | ref: "Course",
60 | unique: true,
61 | autopopulate: { maxDepth: 3 },
62 | },
63 | },
64 | ],
65 |
66 | notifications: [
67 | {
68 | notification: {
69 | type: Schema.Types.ObjectId,
70 | ref: "Notification",
71 | autopopulate: { maxDepth: 2 },
72 | },
73 | },
74 | ],
75 | registered_at: {
76 | type: Date,
77 | default: Date.now,
78 | },
79 | });
80 |
81 | studentSchema.methods.addCourse = function (course) {
82 | // const updatedCourses = [...this.courses];
83 | // updatedCourses.push(course);
84 | // this.courses = updatedCourses;
85 | // return this.courses.save();
86 | return this.courses.push(course);
87 | };
88 |
89 | // studentSchema.plugin(autopopulate);
90 | studentSchema.plugin(require("mongoose-autopopulate"));
91 |
92 | module.exports = mongoose.model("Student", studentSchema);
93 |
--------------------------------------------------------------------------------
/server/models/teacher.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const validator = require("validator");
3 |
4 | const bcrypt = require("bcrypt");
5 | const Schema = mongoose.Schema;
6 |
7 | const teacherSchema = new Schema({
8 | role: {
9 | type: String,
10 | required: true,
11 | enum: ["Student", "Teacher"],
12 | },
13 | username: {
14 | type: String,
15 | require: true,
16 | unique: true,
17 | minlength: 3,
18 | },
19 |
20 | email: {
21 | type: String,
22 | unique: true,
23 | // validate: {
24 | // validator: validator.email,
25 | // message: 'This is not a valid email',
26 | // },
27 | lowercase: true,
28 | unique: true,
29 | },
30 | password: {
31 | type: String,
32 | required: true,
33 | },
34 | firstName: {
35 | type: String,
36 | },
37 | lastName: {
38 | type: String,
39 | },
40 | designation: {
41 | type: String,
42 | required: true,
43 | },
44 | department: {
45 | type: Schema.Types.ObjectId,
46 | ref: "University.departments",
47 | required: true,
48 | },
49 | varsity: {
50 | type: Schema.Types.ObjectId,
51 | ref: "University",
52 | required: true,
53 | autopopulate: { maxDepth: 2 },
54 | },
55 | courses: [
56 | {
57 | course: {
58 | type: Schema.Types.ObjectId,
59 | ref: "Course",
60 | // unique: true,
61 | autopopulate: { maxDepth: 3 },
62 | },
63 | },
64 | ],
65 | registered_at: {
66 | type: Date,
67 | default: Date.now,
68 | },
69 | });
70 | teacherSchema.plugin(require("mongoose-autopopulate"));
71 | module.exports = mongoose.model("Teacher", teacherSchema);
72 |
--------------------------------------------------------------------------------
/server/models/university.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const validator = require("validator");
3 | const Schema = mongoose.Schema;
4 | const universitySchema = new Schema({
5 | name: {
6 | type: String,
7 | require: true,
8 | unique: true,
9 | },
10 |
11 | shortform: {
12 | type: String,
13 | },
14 |
15 | emails: [
16 | {
17 | email: {
18 | type: String,
19 | unique: true,
20 | lowercase: true,
21 | unique: true,
22 | },
23 | },
24 | ],
25 | departments: [
26 | {
27 | name: {
28 | type: String,
29 | unique: false,
30 | },
31 | shortform: {
32 | type: String,
33 | unique: false,
34 | },
35 | },
36 | ],
37 | });
38 | universitySchema.plugin(require('mongoose-autopopulate'));
39 | module.exports = mongoose.model("University", universitySchema);
40 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "online-test",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "nodemon server.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/jspw/WillChange.git"
13 | },
14 | "author": "jspw,sania51",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/jspw/WillChange/issues"
18 | },
19 | "homepage": "https://github.com/jspw/WillChange#readme",
20 | "devDependencies": {
21 | "nodemon": "^2.0.7"
22 | },
23 | "dependencies": {
24 | "bcrypt": "^5.0.0",
25 | "bcryptjs": "^2.4.3",
26 | "body-parser": "^1.19.0",
27 | "compression": "^1.7.4",
28 | "cors": "^2.8.5",
29 | "dotenv": "^8.2.0",
30 | "ejs": "^3.1.5",
31 | "express": "^4.17.1",
32 | "helmet": "^4.4.1",
33 | "jsonwebtoken": "^8.5.1",
34 | "mongodb": "^3.6.3",
35 | "mongoose": "^5.11.13",
36 | "mongoose-autopopulate": "^0.12.3",
37 | "mysql": "^2.18.1",
38 | "pusher": "^4.0.2",
39 | "sequelize": "^6.4.0",
40 | "socket.io": "^3.1.0",
41 | "validator": "^13.5.2",
42 | "xss-clean": "^0.1.1"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/server/routes/authoRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const authController = require('../controllers/auth');
3 |
4 | const router = express.Router();
5 |
6 | router
7 | .route('/login')
8 | .post(authController.getLogin);
9 |
10 | router
11 | .route('/create-student')
12 | .post(authController.postCreateStudent);
13 |
14 | router
15 | .route('/create-teacher')
16 | .post(authController.postCreateTeacher);
17 |
18 |
19 | router
20 | .route('/create-university')
21 | .post(authController.postCreateUniversity);
22 |
23 | module.exports = router;
--------------------------------------------------------------------------------
/server/routes/index.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const NotificationModel = require("../models/notification");
4 |
5 | const studentRouter = require("./studentRoutes");
6 | const teacherRouter = require("./teacherRoutes");
7 | const authRouter = require("./authoRoutes");
8 | const universityRouter = require("./univesityRoutes");
9 |
10 | const errorHandler = require("../controllers/error");
11 | const authenticateJWS = require("../middleware/authenticateJWS");
12 | const apiResponseInJson = require("../middleware/apiResponseInJson");
13 | const { serverError } = require("../middleware/errorHandler");
14 |
15 | router.use("/auth", authRouter);
16 | router.get(
17 | "/notifications",
18 | (authenticateJWS,
19 | (req, res, next) => {
20 | NotificationModel.find()
21 | .then((notifications) => {
22 | console.log(notifications);
23 | apiResponseInJson(res, 200, notifications);
24 | })
25 | .catch((error) => {
26 | console.log(error);
27 | serverError(res);
28 | });
29 | })
30 | );
31 | router.use("/university", universityRouter);
32 | router.use("/student", studentRouter);
33 | router.use("/teacher", teacherRouter);
34 |
35 | router.all(errorHandler);
36 |
37 | module.exports = router;
38 |
--------------------------------------------------------------------------------
/server/routes/studentRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const studentController = require("../controllers/student");
3 | const authenticateJWT = require("../middleware/authenticateJWS");
4 |
5 | const router = express.Router();
6 |
7 | router.route("/user/:id").get(authenticateJWT, studentController.getStudent);
8 |
9 | router
10 | .route("/user/edit/:id")
11 | .get(authenticateJWT, studentController.getEditStudent)
12 | .post(authenticateJWT, studentController.postEditStudent);
13 |
14 | router
15 | .route("/course/add")
16 | .post(authenticateJWT, studentController.postCourseAdd);
17 |
18 | router.route("/exam/:id").get(authenticateJWT, studentController.getExam);
19 |
20 | router.route("/course/:id").get(authenticateJWT, studentController.getCourse);
21 |
22 | router
23 | .route("/exam/mcq/submit/:id")
24 | .post(authenticateJWT, studentController.postMcqSubmit);
25 |
26 | router
27 | .route("/exam/cq/submit/:id")
28 | .post(authenticateJWT, studentController.postCqSubmit);
29 |
30 | router
31 | .route("/exam/mcq/submit/:id")
32 | .get(authenticateJWT, studentController.getMcqSubmit);
33 |
34 | router
35 | .route("/exam/cq/submit/:id")
36 | .get(authenticateJWT, studentController.getCqSubmit);
37 |
38 | module.exports = router;
39 |
--------------------------------------------------------------------------------
/server/routes/teacherRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const { getMcqSubmit } = require("../controllers/student");
3 | const teacherController = require("../controllers/teacher");
4 | const authenticateJWT = require("../middleware/authenticateJWS");
5 |
6 | const router = express.Router();
7 |
8 | router.route("/user/:id").get(authenticateJWT, teacherController.getTeacher);
9 |
10 | router
11 | .route("/user/edit/:id")
12 | .get(authenticateJWT, teacherController.getEditTeacher)
13 | .post(authenticateJWT, teacherController.postEditTeacher);
14 |
15 | router
16 | .route("/course/create")
17 | .post(authenticateJWT, teacherController.postCreateCourse);
18 |
19 | router
20 | .route("/question/mcq/create")
21 | .post(authenticateJWT, teacherController.postCreateMcqQuestion);
22 |
23 | router
24 | .route("/exam/mcq/create")
25 | .post(authenticateJWT, teacherController.postCreateMcqExam);
26 |
27 | router
28 | .route("/question/cq/create")
29 | .post(authenticateJWT, teacherController.postCreateCqQuestion);
30 |
31 | router
32 | .route("/exam/cq/create")
33 | .post(authenticateJWT, teacherController.postCreateCqExam);
34 |
35 | router.route("/exam/:id").get(authenticateJWT, teacherController.getExam);
36 |
37 | router.route("/course/:id").get(authenticateJWT, teacherController.getCourse);
38 |
39 | router
40 | .route("/exam/mcq/submits/:id")
41 | .get(authenticateJWT, teacherController.getMcqSubmits);
42 |
43 | router
44 | .route("/exam/cq/submits/:id")
45 | .get(authenticateJWT, teacherController.getCqSubmits);
46 |
47 | router
48 | .route("/examine/cq/:id")
49 | .post(authenticateJWT, teacherController.postCqExamine);
50 |
51 | router
52 | .route("/exams/all/:id")
53 | .get(authenticateJWT, teacherController.getAllExams);
54 |
55 | module.exports = router;
56 |
--------------------------------------------------------------------------------
/server/routes/univesityRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const universityController = require('../controllers/university');
3 |
4 | const router = express.Router();
5 |
6 | router
7 | .route('/all')
8 | .get(universityController.getUniversities);
9 |
10 | module.exports = router;
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | require("dotenv").config();
3 |
4 | const app = require("./app");
5 |
6 | const socketIo = require("socket.io");
7 |
8 | const http = require("http");
9 |
10 | const examController = require("./controllers/exam");
11 | const notificationController = require("./controllers/notification");
12 |
13 | const mongodbUrl = process.env.MONGO_URL;
14 |
15 | const PORT = process.env.SERVER_PORT;
16 |
17 | let interval;
18 |
19 | const getApiAndEmit = (socket) => {
20 | const response = new Date();
21 | // if (response.getSeconds() > 30)
22 | socket.emit("mcqTimeLimit", response.getSeconds());
23 | // io.emit("mcqTimeLimit", response.getSeconds());
24 | };
25 |
26 | mongoose
27 | .connect(mongodbUrl, {
28 | useNewUrlParser: true,
29 | useUnifiedTopology: true,
30 | useCreateIndex: true,
31 | })
32 | .then(() => {
33 | console.log("Mongodb Connected!");
34 |
35 | const server = http.createServer(app);
36 |
37 | const io = socketIo(server, {
38 | cors: true,
39 | origin: ["*"],
40 | });
41 |
42 | // var clients = 0;
43 |
44 | // examController(io);
45 | // notificationController(io);
46 |
47 |
48 | io.on("connection", (socket) => {
49 | console.log("New client Connected!");
50 | // const ip = socket.handshake.headers || socket.conn.remoteAddress;
51 | // console.log(ip);
52 |
53 | // console.log("Socket ID : ", socket.id);
54 | // console.log("Clients connected : ", clients);
55 |
56 | // app.use((req, res, next) => {
57 | // req.socket = socket;
58 | // next();
59 | // });
60 |
61 | app.set("socketIO",io);
62 |
63 | socket.on("disconnect", (reason) => {
64 | console.log("Client Disconnected!");
65 | console.log("Reason", reason);
66 | });
67 | });
68 |
69 | server.listen(PORT, () => {
70 | console.log(`Server is listening at localhost:${PORT}`);
71 |
72 | });
73 |
74 | // Handle Unhandled Rejections
75 |
76 | process.on("unhandledRejection", (err) => {
77 | console.log("Unhandled Rejection! Shutting down the server...");
78 | console.error(err);
79 |
80 | server.close(() => {
81 | process.exit(1);
82 | });
83 | });
84 | })
85 | .catch((error) => console.log(error));
86 |
--------------------------------------------------------------------------------
/server/utils/apiCallError.js:
--------------------------------------------------------------------------------
1 | exports.apiCallError = (errorMessage, statusCode) => {
2 | res.status(statusCode).json({
3 | status: "FAILED",
4 | comment: errorMessage,
5 | });
6 | };
7 |
--------------------------------------------------------------------------------
/server/utils/catchAsync.js:
--------------------------------------------------------------------------------
1 | const catchAsync = fn => {
2 | return (req, res, next) => {
3 | fn(req, res, next).catch(next);
4 | };
5 | };
6 |
7 | module.exports = catchAsync;
--------------------------------------------------------------------------------
/server/utils/validator.js:
--------------------------------------------------------------------------------
1 | exports.macthPasswordwithRepassword = (password, repassword) => {
2 |
3 | if (password === repassword)
4 | return true;
5 | return false;
6 |
7 | }
8 |
9 |
--------------------------------------------------------------------------------