├── examenvfront ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── logo.jpeg │ │ └── test.png │ ├── app │ │ ├── app.component.css │ │ ├── pages │ │ │ ├── home │ │ │ │ ├── home.component.css │ │ │ │ ├── home.component.html │ │ │ │ ├── home.component.ts │ │ │ │ └── home.component.spec.ts │ │ │ ├── admin │ │ │ │ ├── sidebar │ │ │ │ │ ├── sidebar.component.css │ │ │ │ │ ├── sidebar.component.ts │ │ │ │ │ ├── sidebar.component.spec.ts │ │ │ │ │ └── sidebar.component.html │ │ │ │ ├── welcome │ │ │ │ │ ├── welcome.component.css │ │ │ │ │ ├── welcome.component.html │ │ │ │ │ ├── welcome.component.ts │ │ │ │ │ └── welcome.component.spec.ts │ │ │ │ ├── dashboard │ │ │ │ │ ├── dashboard.component.css │ │ │ │ │ ├── dashboard.component.html │ │ │ │ │ ├── dashboard.component.ts │ │ │ │ │ └── dashboard.component.spec.ts │ │ │ │ ├── view-categories │ │ │ │ │ ├── view-categories.component.css │ │ │ │ │ ├── view-categories.component.html │ │ │ │ │ ├── view-categories.component.spec.ts │ │ │ │ │ └── view-categories.component.ts │ │ │ │ ├── view-quiz-questions │ │ │ │ │ ├── view-quiz-questions.component.css │ │ │ │ │ ├── view-quiz-questions.component.spec.ts │ │ │ │ │ ├── view-quiz-questions.component.html │ │ │ │ │ └── view-quiz-questions.component.ts │ │ │ │ ├── add-quiz │ │ │ │ │ ├── add-quiz.component.css │ │ │ │ │ ├── add-quiz.component.spec.ts │ │ │ │ │ ├── add-quiz.component.ts │ │ │ │ │ └── add-quiz.component.html │ │ │ │ ├── add-category │ │ │ │ │ ├── add-category.component.css │ │ │ │ │ ├── add-category.component.spec.ts │ │ │ │ │ ├── add-category.component.html │ │ │ │ │ └── add-category.component.ts │ │ │ │ ├── add-question │ │ │ │ │ ├── add-question.component.css │ │ │ │ │ ├── add-question.component.spec.ts │ │ │ │ │ ├── add-question.component.ts │ │ │ │ │ └── add-question.component.html │ │ │ │ ├── update-quiz │ │ │ │ │ ├── update-quiz.component.css │ │ │ │ │ ├── update-quiz.component.spec.ts │ │ │ │ │ ├── update-quiz.component.ts │ │ │ │ │ └── update-quiz.component.html │ │ │ │ └── view-quizzes │ │ │ │ │ ├── view-quizzes.component.css │ │ │ │ │ ├── view-quizzes.component.spec.ts │ │ │ │ │ ├── view-quizzes.component.html │ │ │ │ │ └── view-quizzes.component.ts │ │ │ ├── user │ │ │ │ ├── sidebar │ │ │ │ │ ├── sidebar.component.css │ │ │ │ │ ├── sidebar.component.html │ │ │ │ │ ├── sidebar.component.spec.ts │ │ │ │ │ └── sidebar.component.ts │ │ │ │ ├── instructions │ │ │ │ │ ├── instructions.component.css │ │ │ │ │ ├── instructions.component.spec.ts │ │ │ │ │ ├── instructions.component.ts │ │ │ │ │ └── instructions.component.html │ │ │ │ ├── user-dashboard │ │ │ │ │ ├── user-dashboard.component.css │ │ │ │ │ ├── user-dashboard.component.html │ │ │ │ │ ├── user-dashboard.component.ts │ │ │ │ │ └── user-dashboard.component.spec.ts │ │ │ │ ├── start │ │ │ │ │ ├── start.component.css │ │ │ │ │ ├── start.component.spec.ts │ │ │ │ │ ├── start.component.ts │ │ │ │ │ └── start.component.html │ │ │ │ └── load-quiz │ │ │ │ │ ├── load-quiz.component.css │ │ │ │ │ ├── load-quiz.component.spec.ts │ │ │ │ │ ├── load-quiz.component.html │ │ │ │ │ └── load-quiz.component.ts │ │ │ ├── login │ │ │ │ ├── login.component.css │ │ │ │ ├── login.component.spec.ts │ │ │ │ ├── login.component.html │ │ │ │ └── login.component.ts │ │ │ ├── signup │ │ │ │ ├── signup.component.css │ │ │ │ ├── signup.component.spec.ts │ │ │ │ ├── signup.component.ts │ │ │ │ └── signup.component.html │ │ │ └── profile │ │ │ │ ├── profile.component.css │ │ │ │ ├── profile.component.ts │ │ │ │ ├── profile.component.spec.ts │ │ │ │ └── profile.component.html │ │ ├── components │ │ │ ├── footer │ │ │ │ ├── footer.component.css │ │ │ │ ├── footer.component.html │ │ │ │ ├── footer.component.ts │ │ │ │ └── footer.component.spec.ts │ │ │ └── navbar │ │ │ │ ├── navbar.component.css │ │ │ │ ├── navbar.component.spec.ts │ │ │ │ ├── navbar.component.ts │ │ │ │ └── navbar.component.html │ │ ├── services │ │ │ ├── helper.ts │ │ │ ├── user.service.ts │ │ │ ├── admin.guard.spec.ts │ │ │ ├── normal.guard.spec.ts │ │ │ ├── quiz.service.spec.ts │ │ │ ├── user.service.spec.ts │ │ │ ├── login.service.spec.ts │ │ │ ├── category.service.spec.ts │ │ │ ├── question.service.spec.ts │ │ │ ├── category.service.ts │ │ │ ├── normal.guard.ts │ │ │ ├── admin.guard.ts │ │ │ ├── auth.interceptor.ts │ │ │ ├── question.service.ts │ │ │ ├── quiz.service.ts │ │ │ └── login.service.ts │ │ ├── app.component.ts │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app-routing.module.ts │ │ └── app.module.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── main.ts │ ├── index.html │ ├── styles.css │ ├── test.ts │ └── polyfills.ts ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── tasks.json ├── .editorconfig ├── tsconfig.app.json ├── tsconfig.spec.json ├── .browserslistrc ├── .gitignore ├── tsconfig.json ├── README.md ├── package.json ├── karma.conf.js └── angular.json ├── .DS_Store ├── examserver ├── .DS_Store ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── examenv │ │ │ │ └── examserver │ │ │ │ ├── repo │ │ │ │ ├── RoleRepository.java │ │ │ │ ├── CategoryRepository.java │ │ │ │ ├── UserRepository.java │ │ │ │ ├── QuestionRepository.java │ │ │ │ └── QuizRepository.java │ │ │ │ ├── helper │ │ │ │ ├── UserNotFoundException.java │ │ │ │ └── UserFoundException.java │ │ │ │ ├── model │ │ │ │ ├── JwtResponse.java │ │ │ │ ├── Authority.java │ │ │ │ ├── JwtRequest.java │ │ │ │ ├── UserRole.java │ │ │ │ ├── Role.java │ │ │ │ ├── exam │ │ │ │ │ ├── Category.java │ │ │ │ │ ├── Quiz.java │ │ │ │ │ └── Question.java │ │ │ │ └── User.java │ │ │ │ ├── service │ │ │ │ ├── CategoryService.java │ │ │ │ ├── UserService.java │ │ │ │ ├── QuestionService.java │ │ │ │ ├── QuizService.java │ │ │ │ └── impl │ │ │ │ │ ├── UserDetailsServiceImpl.java │ │ │ │ │ ├── CategoryServiceImpl.java │ │ │ │ │ ├── QuestionServiceImpl.java │ │ │ │ │ ├── QuizServiceImpl.java │ │ │ │ │ └── UserServiceImpl.java │ │ │ │ ├── config │ │ │ │ ├── JwtAuthenticationEntryPoint.java │ │ │ │ ├── JwtUtils.java │ │ │ │ ├── MySecurityConfig.java │ │ │ │ └── JwtAuthenticationFilter.java │ │ │ │ ├── controller │ │ │ │ ├── CategoryController.java │ │ │ │ ├── QuizController.java │ │ │ │ ├── UserController.java │ │ │ │ ├── AuthenticateController.java │ │ │ │ └── QuestionController.java │ │ │ │ └── ExamserverApplication.java │ │ └── resources │ │ │ └── application.properties │ └── test │ │ └── java │ │ └── com │ │ └── examenv │ │ └── examserver │ │ └── ExamserverApplicationTests.java ├── .gitignore ├── pom.xml ├── mvnw.cmd └── mvnw └── README.md /examenvfront/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/home/home.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/footer/footer.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/sidebar/sidebar.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/welcome/welcome.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/sidebar/sidebar.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/dashboard/dashboard.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/instructions/instructions.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozen-dev71/Examination/main/.DS_Store -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-categories/view-categories.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/user-dashboard/user-dashboard.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/footer/footer.component.html: -------------------------------------------------------------------------------- 1 |

footer works!

2 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quiz-questions/view-quiz-questions.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/login/login.component.css: -------------------------------------------------------------------------------- 1 | .full-width{ 2 | width: 100%; 3 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/signup/signup.component.css: -------------------------------------------------------------------------------- 1 | .full-width{ 2 | width: 100%; 3 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-quiz/add-quiz.component.css: -------------------------------------------------------------------------------- 1 | .w100{ 2 | width: 100%; 3 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/welcome/welcome.component.html: -------------------------------------------------------------------------------- 1 |

Welcome to ADMIN Panel

-------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-category/add-category.component.css: -------------------------------------------------------------------------------- 1 | .w100{ 2 | width: 100%; 3 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-question/add-question.component.css: -------------------------------------------------------------------------------- 1 | .w100{ 2 | width: 100%; 3 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/update-quiz/update-quiz.component.css: -------------------------------------------------------------------------------- 1 | .w100{ 2 | width: 100%; 3 | } -------------------------------------------------------------------------------- /examserver/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozen-dev71/Examination/main/examserver/.DS_Store -------------------------------------------------------------------------------- /examenvfront/src/app/services/helper.ts: -------------------------------------------------------------------------------- 1 | let baseUrl = "http://localhost:8080" 2 | export default baseUrl; -------------------------------------------------------------------------------- /examenvfront/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /examenvfront/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozen-dev71/Examination/main/examenvfront/src/favicon.ico -------------------------------------------------------------------------------- /examenvfront/src/assets/logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozen-dev71/Examination/main/examenvfront/src/assets/logo.jpeg -------------------------------------------------------------------------------- /examenvfront/src/assets/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozen-dev71/Examination/main/examenvfront/src/assets/test.png -------------------------------------------------------------------------------- /examserver/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frozen-dev71/Examination/main/examserver/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /examenvfront/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/navbar/navbar.component.css: -------------------------------------------------------------------------------- 1 | .example-spacer { 2 | flex: 1 1 auto; 3 | } 4 | .toolbar-color { 5 | background-color: #3778AB; 6 | color: white; 7 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quizzes/view-quizzes.component.css: -------------------------------------------------------------------------------- 1 | .example-header-image { 2 | background-image: url('../../../../assets/test.png'); 3 | background-size: cover; 4 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/start/start.component.css: -------------------------------------------------------------------------------- 1 | 2 | .loader-spinner ::ng-deep .mat-progress-spinner circle, .mat-spinner circle { 3 | stroke: #3778AB; 4 | } 5 | 6 | .mt70{ 7 | margin-top: 70px; 8 | } -------------------------------------------------------------------------------- /examserver/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/profile/profile.component.css: -------------------------------------------------------------------------------- 1 | .profile-image{ 2 | max-width: 150px; 3 | max-height: 150px; 4 | } 5 | 6 | .table { 7 | width: 100%; 8 | border-collapse: collapse; 9 | } 10 | .table tr td { 11 | padding: 15px 20px; 12 | border: 0.5px solid #3778AB; 13 | } -------------------------------------------------------------------------------- /examenvfront/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'examenvfront'; 10 | } 11 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/repo/RoleRepository.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.repo; 2 | 3 | import com.examenv.examserver.model.Role; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface RoleRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/load-quiz/load-quiz.component.css: -------------------------------------------------------------------------------- 1 | .truncate{ 2 | display: block; 3 | white-space: nowrap; 4 | width: 100%; 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | } 8 | .example-header-image { 9 | background-image: url('../../../../assets/test.png'); 10 | background-size: cover; 11 | } -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/repo/CategoryRepository.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.repo; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface CategoryRepository extends JpaRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /examenvfront/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 |
-------------------------------------------------------------------------------- /examenvfront/src/app/pages/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Welcome to Exam Environment

6 | 7 |
8 |
9 |
10 |
-------------------------------------------------------------------------------- /examserver/src/test/java/com/examenv/examserver/ExamserverApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ExamserverApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/repo/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.repo; 2 | 3 | import com.examenv.examserver.model.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface UserRepository extends JpaRepository { 7 | public User findByUsername(String username); 8 | } 9 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/dashboard/dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /examenvfront/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | templateUrl: './home.component.html', 6 | styleUrls: ['./home.component.css'] 7 | }) 8 | export class HomeComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /examenvfront/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/helper/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.helper; 2 | 3 | public class UserNotFoundException extends Exception { 4 | public UserNotFoundException() { 5 | super("User with this Username not found in DB!!"); 6 | } 7 | 8 | public UserNotFoundException(String msg) { super(msg); } 9 | } 10 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/user-dashboard/user-dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/footer/footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-footer', 5 | templateUrl: './footer.component.html', 6 | styleUrls: ['./footer.component.css'] 7 | }) 8 | export class FooterComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/sidebar/sidebar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-sidebar', 5 | templateUrl: './sidebar.component.html', 6 | styleUrls: ['./sidebar.component.css'] 7 | }) 8 | export class SidebarComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/welcome/welcome.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-welcome', 5 | templateUrl: './welcome.component.html', 6 | styleUrls: ['./welcome.component.css'] 7 | }) 8 | export class WelcomeComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/helper/UserFoundException.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.helper; 2 | 3 | public class UserFoundException extends Exception{ 4 | public UserFoundException() { 5 | super("User with this Username is already there in DB!! please try with an unique username"); 6 | } 7 | 8 | public UserFoundException(String msg) { super(msg); } 9 | } 10 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/dashboard/dashboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-dashboard', 5 | templateUrl: './dashboard.component.html', 6 | styleUrls: ['./dashboard.component.css'] 7 | }) 8 | export class DashboardComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/user-dashboard/user-dashboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-user-dashboard', 5 | templateUrl: './user-dashboard.component.html', 6 | styleUrls: ['./user-dashboard.component.css'] 7 | }) 8 | export class UserDashboardComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/user.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import baseUrl from './helper'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class UserService { 9 | 10 | constructor(private http:HttpClient) { 11 | } 12 | 13 | public addUser(user:any){ 14 | return this.http.post(`${baseUrl}/user/`,user); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /examenvfront/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /examenvfront/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/admin.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AdminGuard } from './admin.guard'; 4 | 5 | describe('AdminGuard', () => { 6 | let guard: AdminGuard; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | guard = TestBed.inject(AdminGuard); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(guard).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/normal.guard.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { NormalGuard } from './normal.guard'; 4 | 5 | describe('NormalGuard', () => { 6 | let guard: NormalGuard; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | guard = TestBed.inject(NormalGuard); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(guard).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/repo/QuestionRepository.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.repo; 2 | 3 | import com.examenv.examserver.model.exam.Question; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | import java.util.Set; 8 | 9 | public interface QuestionRepository extends JpaRepository { 10 | Set findByQuiz(Quiz quiz); 11 | } 12 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/quiz.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { QuizService } from './quiz.service'; 4 | 5 | describe('QuizService', () => { 6 | let service: QuizService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(QuizService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { UserService } from './user.service'; 4 | 5 | describe('UserService', () => { 6 | let service: UserService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(UserService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/login.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginService } from './login.service'; 4 | 5 | describe('LoginService', () => { 6 | let service: LoginService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(LoginService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/category.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { CategoryService } from './category.service'; 4 | 5 | describe('CategoryService', () => { 6 | let service: CategoryService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(CategoryService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/question.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { QuestionService } from './question.service'; 4 | 5 | describe('QuestionService', () => { 6 | let service: QuestionService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(QuestionService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/JwtResponse.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model; 2 | 3 | public class JwtResponse { 4 | String token; 5 | 6 | public JwtResponse(String token) { 7 | this.token = token; 8 | } 9 | 10 | public JwtResponse() { 11 | } 12 | 13 | public String getToken() { 14 | return token; 15 | } 16 | 17 | public void setToken(String token) { 18 | this.token = token; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/Authority.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | 5 | public class Authority implements GrantedAuthority { 6 | 7 | private String authority; 8 | 9 | public Authority(String authority) { 10 | this.authority = authority; 11 | } 12 | 13 | @Override 14 | public String getAuthority() { 15 | return this.authority; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/sidebar/sidebar.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | Available Categories 5 |
6 | 9 | 12 |
13 |
-------------------------------------------------------------------------------- /examserver/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #database configuration 2 | spring.datasource.url=jdbc:mysql://localhost:3306/exam?serverTimezone=UTC 3 | spring.datasource.username=root 4 | spring.datasource.password=my-secret-pw 5 | spring.datasource.driver-class=com.cj.jdbc.Driver 6 | 7 | #jpa configuration 8 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect 9 | spring.jpa.hibernate.ddl-auto=update 10 | spring.jpa.show-sql=true 11 | spring.jpa.properties.hibernate.format_sql=true 12 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/CategoryService.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | 5 | import java.util.Set; 6 | 7 | public interface CategoryService { 8 | public Category addCategory(Category category); 9 | public Category updateCategory(Category category); 10 | public Set getCategories(); 11 | public Category getCategory(Long categoryId); 12 | 13 | public void deleteCategory(Long categoryId); 14 | } 15 | -------------------------------------------------------------------------------- /examserver/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service; 2 | 3 | import com.examenv.examserver.model.User; 4 | import com.examenv.examserver.model.UserRole; 5 | 6 | import java.util.Set; 7 | 8 | public interface UserService { 9 | 10 | //Create User 11 | public User createUser(User user, Set userRoles) throws Exception; 12 | 13 | //get user by username 14 | public User getUser(String username); 15 | 16 | 17 | //delete user by id 18 | public void deleteUser(Long userId); 19 | } 20 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/category.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import baseUrl from './helper'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class CategoryService { 9 | 10 | constructor(private _http: HttpClient) { } 11 | 12 | public categories() { 13 | return this._http.get(`${baseUrl}/category/`) 14 | } 15 | 16 | 17 | //add new category 18 | public addCategory(category:any){ 19 | return this._http.post(`${baseUrl}/category/`,category); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examenvfront/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/repo/QuizRepository.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.repo; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | import java.util.List; 8 | 9 | public interface QuizRepository extends JpaRepository { 10 | public List findBycategory(Category category); 11 | 12 | public List findByActive(Boolean b); 13 | public List findByCategoryAndActive(Category c, Boolean b); 14 | } 15 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-categories/view-categories.component.html: -------------------------------------------------------------------------------- 1 | 2 |

All Categories

3 | 4 | 5 | category 6 |
{{cat["title"]}}
7 |
{{cat["description"]}}
8 | 9 |
10 |
11 | 12 |
13 | 14 |
15 | 16 |
-------------------------------------------------------------------------------- /examenvfront/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Examenvfront 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examenvfront/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/QuestionService.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service; 2 | 3 | import com.examenv.examserver.model.exam.Question; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | 6 | import java.util.Set; 7 | 8 | public interface QuestionService { 9 | public Question addQuestion(Question question); 10 | 11 | public Question updateQuestion(Question question); 12 | 13 | public Set getQuestion(); 14 | 15 | public Question getQuestion(Long questionId); 16 | 17 | public Set getQuestionsOfQuiz(Quiz quiz); 18 | 19 | public void deleteQuestion(Long questionId); 20 | 21 | 22 | public Question get(Long questionsId); 23 | } 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(HomeComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(LoginComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/profile/profile.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { LoginService } from 'src/app/services/login.service'; 3 | 4 | @Component({ 5 | selector: 'app-profile', 6 | templateUrl: './profile.component.html', 7 | styleUrls: ['./profile.component.css'] 8 | }) 9 | export class ProfileComponent implements OnInit { 10 | user = null; 11 | 12 | constructor(private login: LoginService) { } 13 | 14 | ngOnInit(): void { 15 | 16 | // this.user = this.login.getUser(); 17 | this.login.getCurrentUser().subscribe( 18 | (user:any)=> { 19 | this.user = user; 20 | }, 21 | (error)=> { 22 | alert('error'); 23 | } 24 | ); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/signup/signup.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SignupComponent } from './signup.component'; 4 | 5 | describe('SignupComponent', () => { 6 | let component: SignupComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SignupComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(SignupComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/start/start.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { StartComponent } from './start.component'; 4 | 5 | describe('StartComponent', () => { 6 | let component: StartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ StartComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(StartComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/QuizService.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | public interface QuizService { 10 | public Quiz addQuiz(Quiz quiz); 11 | public Quiz updateQuiz(Quiz quiz); 12 | 13 | public Set getQuizzes(); 14 | public Quiz getQuiz(Long quizId); 15 | public void deleteQuiz(Long quizId); 16 | 17 | 18 | public List getQuizzesOfCategory(Category category); 19 | 20 | public List getActiveQuizzes(); 21 | public List getActiveQuizzesOfCategory(Category category); 22 | } 23 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/footer/footer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { FooterComponent } from './footer.component'; 4 | 5 | describe('FooterComponent', () => { 6 | let component: FooterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ FooterComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(FooterComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/navbar/navbar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NavbarComponent } from './navbar.component'; 4 | 5 | describe('NavbarComponent', () => { 6 | let component: NavbarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ NavbarComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(NavbarComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/profile/profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProfileComponent } from './profile.component'; 4 | 5 | describe('ProfileComponent', () => { 6 | let component: ProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ProfileComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ProfileComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/sidebar/sidebar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SidebarComponent } from './sidebar.component'; 4 | 5 | describe('SidebarComponent', () => { 6 | let component: SidebarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SidebarComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(SidebarComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/welcome/welcome.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { WelcomeComponent } from './welcome.component'; 4 | 5 | describe('WelcomeComponent', () => { 6 | let component: WelcomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ WelcomeComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(WelcomeComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/sidebar/sidebar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SidebarComponent } from './sidebar.component'; 4 | 5 | describe('SidebarComponent', () => { 6 | let component: SidebarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SidebarComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(SidebarComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-quiz/add-quiz.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AddQuizComponent } from './add-quiz.component'; 4 | 5 | describe('AddQuizComponent', () => { 6 | let component: AddQuizComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ AddQuizComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(AddQuizComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/load-quiz/load-quiz.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoadQuizComponent } from './load-quiz.component'; 4 | 5 | describe('LoadQuizComponent', () => { 6 | let component: LoadQuizComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ LoadQuizComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(LoadQuizComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/JwtRequest.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model; 2 | 3 | public class JwtRequest { 4 | String username; 5 | String password; 6 | 7 | public JwtRequest() { 8 | } 9 | 10 | public JwtRequest(String username, String password) { 11 | this.username = username; 12 | this.password = password; 13 | } 14 | 15 | public String getUsername() { 16 | return username; 17 | } 18 | 19 | public void setUsername(String username) { 20 | this.username = username; 21 | } 22 | 23 | public String getPassword() { 24 | return password; 25 | } 26 | 27 | public void setPassword(String password) { 28 | this.password = password; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/dashboard/dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DashboardComponent } from './dashboard.component'; 4 | 5 | describe('DashboardComponent', () => { 6 | let component: DashboardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ DashboardComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(DashboardComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; background: #e1f5fe; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | 6 | .text-center { 7 | text-align: center; 8 | } 9 | .logo{ 10 | width: 150px; 11 | } 12 | 13 | .ml20 { 14 | margin-left: 20px !important; 15 | } 16 | .mr20 { 17 | margin-right: 20px !important; 18 | } 19 | .mt20 { 20 | margin-top: 20px !important; 21 | } 22 | .mb20 { 23 | margin-bottom: 20px !important; 24 | } 25 | 26 | .ml10 { 27 | margin-left: 10px !important; 28 | } 29 | .mr10 { 30 | margin-right: 10px !important; 31 | } 32 | .mt10 { 33 | margin-top: 10px !important; 34 | } 35 | .mb10 { 36 | margin-bottom: 10px !important; 37 | } -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/update-quiz/update-quiz.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UpdateQuizComponent } from './update-quiz.component'; 4 | 5 | describe('UpdateQuizComponent', () => { 6 | let component: UpdateQuizComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ UpdateQuizComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(UpdateQuizComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-category/add-category.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AddCategoryComponent } from './add-category.component'; 4 | 5 | describe('AddCategoryComponent', () => { 6 | let component: AddCategoryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ AddCategoryComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(AddCategoryComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-question/add-question.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AddQuestionComponent } from './add-question.component'; 4 | 5 | describe('AddQuestionComponent', () => { 6 | let component: AddQuestionComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ AddQuestionComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(AddQuestionComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quizzes/view-quizzes.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ViewQuizzesComponent } from './view-quizzes.component'; 4 | 5 | describe('ViewQuizzesComponent', () => { 6 | let component: ViewQuizzesComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ViewQuizzesComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ViewQuizzesComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/instructions/instructions.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { InstructionsComponent } from './instructions.component'; 4 | 5 | describe('InstructionsComponent', () => { 6 | let component: InstructionsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ InstructionsComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(InstructionsComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/user-dashboard/user-dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserDashboardComponent } from './user-dashboard.component'; 4 | 5 | describe('UserDashboardComponent', () => { 6 | let component: UserDashboardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ UserDashboardComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(UserDashboardComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-categories/view-categories.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ViewCategoriesComponent } from './view-categories.component'; 4 | 5 | describe('ViewCategoriesComponent', () => { 6 | let component: ViewCategoriesComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ViewCategoriesComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ViewCategoriesComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quiz-questions/view-quiz-questions.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ViewQuizQuestionsComponent } from './view-quiz-questions.component'; 4 | 5 | describe('ViewQuizQuestionsComponent', () => { 6 | let component: ViewQuizQuestionsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ ViewQuizQuestionsComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ViewQuizQuestionsComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/normal.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | import { LoginService } from './login.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class NormalGuard implements CanActivate { 10 | constructor(private login: LoginService,private router: Router){} 11 | canActivate( 12 | route: ActivatedRouteSnapshot, 13 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { 14 | 15 | if (this.login.isLoggedIn() && this.login.getUserRole() == 'NORMAL'){ 16 | return true; 17 | } 18 | 19 | this.router.navigate(['login']); 20 | 21 | return false; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /examenvfront/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | (id: string): T; 13 | keys(): string[]; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting(), 21 | ); 22 | 23 | // Then we find all the tests. 24 | const context = require.context('./', true, /\.spec\.ts$/); 25 | // And load the modules. 26 | context.keys().forEach(context); 27 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/admin.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; 3 | import { Observable } from 'rxjs'; 4 | import { LoginService } from './login.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class AdminGuard implements CanActivate { 10 | constructor(private login: LoginService,private router: Router){} 11 | canActivate( 12 | route: ActivatedRouteSnapshot, 13 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { 14 | 15 | if (this.login.isLoggedIn() && this.login.getUserRole() == 'ADMIN'){ 16 | return true; 17 | } 18 | 19 | this.router.navigate(['login']); 20 | 21 | 22 | return false; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-categories/view-categories.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CategoryService } from 'src/app/services/category.service'; 3 | import Swal from 'sweetalert2'; 4 | 5 | @Component({ 6 | selector: 'app-view-categories', 7 | templateUrl: './view-categories.component.html', 8 | styleUrls: ['./view-categories.component.css'] 9 | }) 10 | export class ViewCategoriesComponent implements OnInit { 11 | 12 | categories= []; 13 | 14 | constructor(private _category: CategoryService) { } 15 | 16 | ngOnInit(): void { 17 | this._category.categories().subscribe((data:any)=> { 18 | this.categories = data; 19 | console.log(this.categories); 20 | }, 21 | (error)=>{ 22 | console.log(error); 23 | Swal.fire("Error!!","Error on loading data","error"); 24 | } 25 | ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/config/JwtAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.config; 2 | 3 | import org.springframework.security.core.AuthenticationException; 4 | import org.springframework.security.web.AuthenticationEntryPoint; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | @Component 13 | public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { 14 | @Override 15 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 16 | response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized : Server"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/sidebar/sidebar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { MatSnackBar } from '@angular/material/snack-bar'; 3 | import { CategoryService } from 'src/app/services/category.service'; 4 | 5 | @Component({ 6 | selector: 'app-sidebar-user', 7 | templateUrl: './sidebar.component.html', 8 | styleUrls: ['./sidebar.component.css'] 9 | }) 10 | export class SidebarComponent implements OnInit { 11 | 12 | categories:any; 13 | 14 | constructor(private _category: CategoryService,private _snack:MatSnackBar) { } 15 | 16 | ngOnInit(): void { 17 | this._category.categories().subscribe( 18 | (data:any)=> { 19 | this.categories = data; 20 | }, 21 | (error)=>{ 22 | this._snack.open("Error on loading Categories from server","OK",{ 23 | duration:2500 24 | }); 25 | } 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { LoginService } from 'src/app/services/login.service'; 3 | 4 | @Component({ 5 | selector: 'app-navbar', 6 | templateUrl: './navbar.component.html', 7 | styleUrls: ['./navbar.component.css'] 8 | }) 9 | export class NavbarComponent implements OnInit { 10 | 11 | isLoggedIn = false; 12 | user = null; 13 | 14 | 15 | constructor(public login: LoginService) { } 16 | 17 | ngOnInit(): void { 18 | this.isLoggedIn = this.login.isLoggedIn(); 19 | this.user = this.login.getUser(); 20 | this.login.loginStatusSubject.asObservable().subscribe(data => { 21 | this.isLoggedIn = this.login.isLoggedIn(); 22 | this.user = this.login.getUser(); 23 | }); 24 | } 25 | 26 | public logout(){ 27 | this.login.logout(); 28 | window.location.reload(); 29 | // this.login.loginStatusSubject.next(false); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/sidebar/sidebar.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | Menu 5 |
6 | 9 | 12 | 15 | 18 | 21 | 24 |
25 |
-------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model; 2 | 3 | import javax.persistence.*; 4 | 5 | @Entity 6 | public class UserRole { 7 | @Id 8 | @GeneratedValue(strategy = GenerationType.AUTO) 9 | private Long userRoleId; 10 | 11 | //user 12 | @ManyToOne(fetch = FetchType.EAGER) 13 | private User user; 14 | 15 | @ManyToOne 16 | private Role role; 17 | 18 | public UserRole() { 19 | } 20 | 21 | public Long getUserRoleId() { 22 | return userRoleId; 23 | } 24 | 25 | public void setUserRoleId(Long userRoleId) { 26 | this.userRoleId = userRoleId; 27 | } 28 | 29 | public User getUser() { 30 | return user; 31 | } 32 | 33 | public void setUser(User user) { 34 | this.user = user; 35 | } 36 | 37 | public Role getRole() { 38 | return role; 39 | } 40 | 41 | public void setRole(Role role) { 42 | this.role = role; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/auth.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HTTP_INTERCEPTORS } from "@angular/common/http"; 2 | import { Injectable } from "@angular/core"; 3 | import { Observable } from "rxjs"; 4 | import { LoginService } from "./login.service"; 5 | 6 | @Injectable() 7 | export class AuthInterceptor implements HttpInterceptor { 8 | constructor(private login: LoginService){} 9 | 10 | intercept(req: HttpRequest, next: HttpHandler): Observable> { 11 | //add jwt token local storage request 12 | let authReq = req; 13 | const token = this.login.getToken(); 14 | console.log("Inside interceptor"); 15 | if(token != null){ 16 | authReq = authReq.clone({setHeaders: {Authorization: `Bearer ${token}`}, 17 | }); 18 | } 19 | 20 | return next.handle(authReq); 21 | } 22 | 23 | } 24 | 25 | export const authInterceptorProviders = [ 26 | { 27 | provide: HTTP_INTERCEPTORS, 28 | useClass: AuthInterceptor, 29 | multi: true, 30 | } 31 | ] -------------------------------------------------------------------------------- /examenvfront/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "es2020", 20 | "module": "es2020", 21 | "lib": [ 22 | "es2020", 23 | "dom" 24 | ] 25 | }, 26 | "angularCompilerOptions": { 27 | "enableI18nLegacyMessageIdFormat": false, 28 | "strictInjectionParameters": true, 29 | "strictInputAccessModifiers": true, 30 | "strictTemplates": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-category/add-category.component.html: -------------------------------------------------------------------------------- 1 | 2 |

Add New Category

3 | 4 |
5 |
6 |
7 | 8 |
9 | 10 | Title 11 | 12 | 13 | 14 | 15 | 16 | Description 17 | 18 | 19 | 20 |
21 | 22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 |
30 |
-------------------------------------------------------------------------------- /examenvfront/src/app/services/question.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import baseUrl from './helper'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class QuestionService { 9 | 10 | constructor(private _http:HttpClient) { } 11 | 12 | public getQuestionsOfQuiz(qId:any){ 13 | return this._http.get(`${baseUrl}/question/quiz/all/${qId}`); 14 | } 15 | 16 | public getQuestionsOfQuizForTest(qId:any){ 17 | return this._http.get(`${baseUrl}/question/quiz/${qId}`); 18 | } 19 | 20 | 21 | //add question 22 | public addQuestion(question:any){ 23 | return this._http.post(`${baseUrl}/question/`, question); 24 | } 25 | 26 | 27 | // delete question 28 | public deleteQuestion(questionId:any){ 29 | return this._http.delete(`${baseUrl}/question/${questionId}`); 30 | } 31 | 32 | 33 | // evaluate quiz 34 | public evaluateQuiz(questions:any){ 35 | return this._http.post(`${baseUrl}/question/eval-quiz`, questions); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/impl/UserDetailsServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service.impl; 2 | 3 | import com.examenv.examserver.model.User; 4 | import com.examenv.examserver.repo.UserRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | import org.springframework.security.core.userdetails.UserDetailsService; 8 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | public class UserDetailsServiceImpl implements UserDetailsService { 13 | 14 | @Autowired 15 | private UserRepository userRepository; 16 | 17 | @Override 18 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 19 | User user = this.userRepository.findByUsername(username); 20 | if (user == null){ 21 | System.out.println("User not found"); 22 | throw new UsernameNotFoundException("No user found!!"); 23 | } 24 | return user; 25 | } 26 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Examination 2 | Project Aim: 3 | 4 | Examination is a web project that is for the users those are want to improve their knowledges. 5 | 6 | ## About the Project 7 | - All of the Datas fetched from an API(those are created from the back-end side). 8 | - Admin can create and delete categories and quizzes. 9 | - Admin can make the quizzes deactive. 10 | - Users can only see active quizzes. 11 | - You cannot reach the pages without logging in as a user(used Routing Guards) 12 | 13 | ## Technologies used 14 | + [X] Java 15 | + [X] Springboot 16 | + [X] BCryptPasswordEncoder 17 | + [X] JSON Web Tokens 18 | + [X] HTTP 19 | + [X] Database(MySQL) 20 | + [X] HTML and CSS 21 | + [X] Bootstrap 22 | + [X] Typescript 23 | + [X] Angular 24 | + [X] Angular Material 25 | + [X] MatSnackBar and SweetAlert 26 | + [X] Ngx-Ui-Loader 27 | 28 | # Screen Recordings 29 | 30 | ## Admin Page 31 | 32 | https://user-images.githubusercontent.com/44535117/204846392-7234822a-d591-44ef-9ef7-5142c4647a0a.mov 33 | 34 | 35 | ## Normal User Page 36 | 37 | 38 | https://user-images.githubusercontent.com/44535117/204846968-8486ffdf-9123-41e1-a9a8-69d405334d94.mov 39 | 40 | -------------------------------------------------------------------------------- /examenvfront/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /examenvfront/README.md: -------------------------------------------------------------------------------- 1 | # Examenvfront 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.6. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /examenvfront/src/app/components/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | local_library 5 | 6 | Examination 7 | 8 | 9 | 13 | Login 14 | 15 | 16 | 20 | Register 21 | 22 | 23 | 27 | {{ user['username'] }} 28 | 29 | 30 | 34 | Logout 35 | 36 | 37 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/Role.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model; 2 | 3 | import javax.persistence.*; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | @Entity 8 | @Table(name = "roles") 9 | public class Role { 10 | 11 | @Id 12 | private Long roleId; 13 | private String roleName; 14 | 15 | @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy = "role") 16 | private Set userRoles = new HashSet<>(); 17 | 18 | public Role() { 19 | } 20 | 21 | public Role(Long roleId, String roleName) { 22 | this.roleId = roleId; 23 | this.roleName = roleName; 24 | } 25 | 26 | public Set getUserRoles() { 27 | return userRoles; 28 | } 29 | 30 | public void setUserRoles(Set userRoles) { 31 | this.userRoles = userRoles; 32 | } 33 | 34 | 35 | 36 | public Long getRoleId() { 37 | return roleId; 38 | } 39 | 40 | public void setRoleId(Long roleId) { 41 | this.roleId = roleId; 42 | } 43 | 44 | public String getRoleName() { 45 | return roleName; 46 | } 47 | 48 | public void setRoleName(String roleName) { 49 | this.roleName = roleName; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examenvfront/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'examenvfront'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('examenvfront'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement as HTMLElement; 33 | expect(compiled.querySelector('.content span')?.textContent).toContain('examenvfront app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-category/add-category.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { MatSnackBar } from '@angular/material/snack-bar'; 3 | import { CategoryService } from 'src/app/services/category.service'; 4 | import Swal from 'sweetalert2'; 5 | 6 | @Component({ 7 | selector: 'app-add-category', 8 | templateUrl: './add-category.component.html', 9 | styleUrls: ['./add-category.component.css'] 10 | }) 11 | export class AddCategoryComponent implements OnInit { 12 | 13 | category = { 14 | title: '', 15 | description: '' 16 | } 17 | 18 | constructor(private _category: CategoryService, private _snack: MatSnackBar) { } 19 | 20 | ngOnInit(): void { 21 | } 22 | 23 | formSubmit() { 24 | if (this.category.title.trim() == '' || this.category.title == null){ 25 | this._snack.open("Title Required","OK", { 26 | duration: 2500 27 | }); 28 | return; 29 | } 30 | 31 | this._category.addCategory(this.category).subscribe( 32 | (data:any)=> { 33 | this.category.title = ''; 34 | this.category.description = ''; 35 | Swal.fire("Success!","Category has been added successfully","success"); 36 | }, 37 | (error)=> { 38 | Swal.fire("Error!","Server error","error"); 39 | } 40 | ); 41 | 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quizzes/view-quizzes.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | {{quiz["title"]}} 6 | 7 | 8 | {{quiz["category"]["title"]}} 9 | 10 |
11 | 12 | 13 |

{{quiz["description"]}}

14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 |
29 | 30 |
-------------------------------------------------------------------------------- /examenvfront/src/app/services/quiz.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import baseUrl from './helper'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class QuizService { 9 | 10 | constructor(private _http:HttpClient) { } 11 | 12 | public quizzes(){ 13 | return this._http.get(`${baseUrl}/quiz/`); 14 | } 15 | 16 | public addQuiz(quiz:any){ 17 | return this._http.post(`${baseUrl}/quiz/`,quiz); 18 | } 19 | 20 | public deleteQuiz(qId: any){ 21 | return this._http.delete(`${baseUrl}/quiz/${qId}`); 22 | } 23 | 24 | 25 | //get single quiz 26 | public getQuiz(qId: any){ 27 | return this._http.get(`${baseUrl}/quiz/${qId}`); 28 | } 29 | 30 | //update quiz 31 | public updateQuiz(quiz: any){ 32 | return this._http.put(`${baseUrl}/quiz/`,quiz); 33 | } 34 | 35 | //get quizzes of category 36 | public getQuizzesOfCategory(cId:any){ 37 | return this._http.get(`${baseUrl}/quiz/category/${cId}`); 38 | } 39 | 40 | //get active quizzes 41 | public getActiveQuizzes(){ 42 | return this._http.get(`${baseUrl}/quiz/active`); 43 | } 44 | 45 | //get active quizzes of category 46 | public getActiveQuizzesOfCategory(cId:any){ 47 | return this._http.get(`${baseUrl}/quiz/category/active/${cId}`); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /examenvfront/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examenvfront", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^14.2.0", 14 | "@angular/cdk": "^13.0.0", 15 | "@angular/common": "^14.2.0", 16 | "@angular/compiler": "^14.2.0", 17 | "@angular/core": "^14.2.0", 18 | "@angular/forms": "^14.2.0", 19 | "@angular/material": "^13.0.0", 20 | "@angular/platform-browser": "^14.2.0", 21 | "@angular/platform-browser-dynamic": "^14.2.0", 22 | "@angular/router": "^14.2.0", 23 | "bootstrap-grid-only-css": "^4.1.3", 24 | "ngx-ui-loader": "^13.0.0", 25 | "rxjs": "~7.5.0", 26 | "sweetalert2": "^11.6.10", 27 | "tslib": "^2.3.0", 28 | "zone.js": "~0.11.4" 29 | }, 30 | "devDependencies": { 31 | "@angular-devkit/build-angular": "^14.2.6", 32 | "@angular/cli": "~14.2.6", 33 | "@angular/compiler-cli": "^14.2.0", 34 | "@types/jasmine": "~4.0.0", 35 | "jasmine-core": "~4.3.0", 36 | "karma": "~6.4.0", 37 | "karma-chrome-launcher": "~3.1.0", 38 | "karma-coverage": "~2.2.0", 39 | "karma-jasmine": "~5.1.0", 40 | "karma-jasmine-html-reporter": "~2.0.0", 41 | "typescript": "~4.7.2" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/load-quiz/load-quiz.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Available Quizzes

4 |
5 |
6 | 7 | 8 | 9 |
10 | 11 | {{quiz.title}} 12 | 13 | 14 | {{quiz.category.title}} 15 | 16 |
17 | 18 | 19 |

{{quiz.description}}

20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |
31 | 32 | 33 |

COULDN'T FOUND ANY AVAILABLE QUIZ FOR THIS CATEGORY

34 |
35 |
36 |
37 |
38 |
39 |
-------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/exam/Category.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model.exam; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import javax.persistence.*; 6 | import java.util.LinkedHashSet; 7 | import java.util.Set; 8 | 9 | @Entity 10 | @Table(name = "category") 11 | public class Category { 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.AUTO) 14 | private Long cId; 15 | 16 | private String title; 17 | private String description; 18 | 19 | @OneToMany(mappedBy = "category", cascade = CascadeType.ALL) 20 | @JsonIgnore 21 | private Set quizzes = new LinkedHashSet<>(); 22 | 23 | public Category() { 24 | } 25 | 26 | public Category(Long cId, String title, String description) { 27 | this.cId = cId; 28 | this.title = title; 29 | this.description = description; 30 | } 31 | 32 | public Long getcId() { 33 | return cId; 34 | } 35 | 36 | public void setcId(Long cId) { 37 | this.cId = cId; 38 | } 39 | 40 | public String getTitle() { 41 | return title; 42 | } 43 | 44 | public void setTitle(String title) { 45 | this.title = title; 46 | } 47 | 48 | public String getDescription() { 49 | return description; 50 | } 51 | 52 | public void setDescription(String description) { 53 | this.description = description; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/instructions/instructions.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { QuizService } from 'src/app/services/quiz.service'; 4 | import Swal from 'sweetalert2'; 5 | 6 | @Component({ 7 | selector: 'app-instructions', 8 | templateUrl: './instructions.component.html', 9 | styleUrls: ['./instructions.component.css'] 10 | }) 11 | export class InstructionsComponent implements OnInit { 12 | qId:any; 13 | quiz:any; 14 | 15 | constructor(private _router: ActivatedRoute, private _quiz: QuizService, private _route:Router) { } 16 | 17 | ngOnInit(): void { 18 | this.qId = this._router.snapshot.params["qid"]; 19 | 20 | this._quiz.getQuiz(this.qId).subscribe( 21 | (data:any)=>{ 22 | this.quiz = data; 23 | }, 24 | (error)=>{{ 25 | console.log(error); 26 | }} 27 | ); 28 | } 29 | 30 | startQuiz(){ 31 | Swal.fire( 32 | { 33 | title: 'Do you want to start the quiz?', 34 | showCancelButton: true, 35 | confirmButtonText: 'Start', 36 | denyButtonText: `Don't Start`, 37 | icon: 'info' 38 | } 39 | ).then( 40 | (result)=>{ 41 | if(result.isConfirmed){ 42 | this._route.navigate(['/start/'+this.qId]); 43 | }else{ 44 | Swal.fire("Denied","OK","warning"); 45 | } 46 | } 47 | ); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/login/login.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 | 8 |
9 | 10 |
11 |

Login

12 | 13 | 14 |
15 | 16 | 17 | Username 18 | 23 | Valid Username 24 | 25 | 26 | 27 | 28 | Password 29 | 35 | 36 | 37 |
38 | 39 | 40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 |
-------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/load-quiz/load-quiz.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { QuizService } from 'src/app/services/quiz.service'; 4 | 5 | @Component({ 6 | selector: 'app-load-quiz', 7 | templateUrl: './load-quiz.component.html', 8 | styleUrls: ['./load-quiz.component.css'] 9 | }) 10 | export class LoadQuizComponent implements OnInit { 11 | 12 | catId:any; 13 | quizzes:any; 14 | 15 | constructor(private _route: ActivatedRoute, private _quiz: QuizService) { } 16 | 17 | ngOnInit(): void { 18 | this._route.params.subscribe( 19 | (params)=>{ 20 | this.catId = params["catId"]; 21 | if(this.catId == 0){ 22 | //Load all quizzes 23 | this._quiz.getActiveQuizzes().subscribe( 24 | (data:any)=>{ 25 | this.quizzes = data; 26 | console.log(this.quizzes); 27 | }, 28 | (error)=>{ 29 | console.log(error); 30 | } 31 | ); 32 | }else{ 33 | //load specific quiz 34 | this.quizzes = this._quiz.getActiveQuizzesOfCategory(this.catId).subscribe( 35 | (data:any)=>{ 36 | this.quizzes = data; 37 | console.log(this.quizzes); 38 | }, 39 | (error)=>{ 40 | console.log(error); 41 | } 42 | ); 43 | } 44 | } 45 | ); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/impl/CategoryServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service.impl; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | import com.examenv.examserver.repo.CategoryRepository; 5 | import com.examenv.examserver.service.CategoryService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.LinkedHashSet; 10 | import java.util.Set; 11 | @Service 12 | public class CategoryServiceImpl implements CategoryService { 13 | 14 | @Autowired 15 | private CategoryRepository categoryRepository; 16 | 17 | @Override 18 | public Category addCategory(Category category) { 19 | return this.categoryRepository.save(category); 20 | } 21 | 22 | @Override 23 | public Category updateCategory(Category category) { 24 | return this.categoryRepository.save(category); 25 | } 26 | 27 | @Override 28 | public Set getCategories() { 29 | return new LinkedHashSet<>(this.categoryRepository.findAll()); 30 | } 31 | 32 | @Override 33 | public Category getCategory(Long categoryId) { 34 | return this.categoryRepository.findById(categoryId).get(); 35 | } 36 | 37 | @Override 38 | public void deleteCategory(Long categoryId) { 39 | 40 | Category category = new Category(); 41 | category.setcId(categoryId); 42 | this.categoryRepository.delete(category); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/signup/signup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { MatSnackBar } from '@angular/material/snack-bar'; 3 | import { UserService } from 'src/app/services/user.service'; 4 | import Swal from 'sweetalert2'; 5 | 6 | @Component({ 7 | selector: 'app-signup', 8 | templateUrl: './signup.component.html', 9 | styleUrls: ['./signup.component.css'] 10 | }) 11 | export class SignupComponent implements OnInit { 12 | 13 | constructor(private userService: UserService, private snack:MatSnackBar) { } 14 | 15 | public user = { 16 | username: '', 17 | password: '', 18 | firstName: '', 19 | lastName: '', 20 | email: '', 21 | phone: '', 22 | 23 | } 24 | 25 | ngOnInit(): void { 26 | } 27 | 28 | formSubmit(){ 29 | console.log(this.user); 30 | if (this.user.username == '' || this.user.username == null) { 31 | this.snack.open("Username is required!!", "Ok", { 32 | duration: 2500, 33 | verticalPosition: 'top', 34 | }); 35 | return; 36 | } 37 | 38 | /* Add User- User Service */ 39 | this.userService.addUser(this.user).subscribe( 40 | (data:any) => { 41 | console.log(data); 42 | 43 | Swal.fire('Success done!!','User id is ' + data.id, 'success'); 44 | }, 45 | (error)=> { 46 | console.log(error); 47 | this.snack.open("Something went Wrong!", "Ok", { 48 | duration: 2500, 49 | verticalPosition: 'top', 50 | }); 51 | } 52 | ); 53 | 54 | } 55 | 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quiz-questions/view-quiz-questions.component.html: -------------------------------------------------------------------------------- 1 |

Questions of {{ qTitle}}

2 | 3 |
4 |
5 | 6 |
7 | 8 |
9 | 10 |
11 | 12 | 13 | 14 |

15 | Q.{{ i + 1 }} {{ quest["content"]}} 16 |

17 | 18 |
19 |
20 |
21 |

1) {{quest["option1"]}}

22 |
23 |
24 |

2) {{quest["option2"]}}

25 |
26 |
27 |
28 |
29 |

3) {{quest["option3"]}}

30 |
31 |
32 |

4) {{quest["option4"]}}

33 |
34 |
35 | 36 |

Correct Answer: {{quest["answer"]}}

37 |
38 | 39 |
40 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |
48 | 49 | -------------------------------------------------------------------------------- /examenvfront/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | jasmine: { 17 | // you can add configuration options for Jasmine here 18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html 19 | // for example, you can disable the random execution with `random: false` 20 | // or set a specific seed with `seed: 4321` 21 | }, 22 | clearContext: false // leave Jasmine Spec Runner output visible in browser 23 | }, 24 | jasmineHtmlReporter: { 25 | suppressAll: true // removes the duplicated traces 26 | }, 27 | coverageReporter: { 28 | dir: require('path').join(__dirname, './coverage/examenvfront'), 29 | subdir: '.', 30 | reporters: [ 31 | { type: 'html' }, 32 | { type: 'text-summary' } 33 | ] 34 | }, 35 | reporters: ['progress', 'kjhtml'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false, 42 | restartOnFileChange: true 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/profile/profile.component.html: -------------------------------------------------------------------------------- 1 | 2 |

Your Profile Details

3 | 4 |
5 |
6 |
7 | 8 | 9 |

{{user['firstName']}} {{user['lastName']}}

10 |
11 | 12 |
13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Username{{user['username']}}
User-id{{user['id']}}
Phone{{user['phone']}}
Role{{user["authorities"][0]["authority"]}}
Status{{user['enabled']? "ACTIVE": "NOTACTIVE"}}
47 |
48 |
49 |
50 |
51 |
52 | 53 | 54 | 55 | 56 |
-------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quizzes/view-quizzes.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { QuizService } from 'src/app/services/quiz.service'; 3 | import Swal from 'sweetalert2'; 4 | 5 | @Component({ 6 | selector: 'app-view-quizzes', 7 | templateUrl: './view-quizzes.component.html', 8 | styleUrls: ['./view-quizzes.component.css'] 9 | }) 10 | export class ViewQuizzesComponent implements OnInit { 11 | 12 | quizzes = [ 13 | { 14 | qId:0, 15 | title:'', 16 | description: '', 17 | category: { 18 | title:'', 19 | }, 20 | maxMark: '', 21 | numberOfQuestions: '' 22 | 23 | } 24 | ]; 25 | 26 | constructor(private _quiz: QuizService) { } 27 | 28 | ngOnInit(): void { 29 | this._quiz.quizzes().subscribe( 30 | (data:any)=> { 31 | this.quizzes = data; 32 | console.log(this.quizzes); 33 | }, 34 | (error)=> { 35 | console.log(error); 36 | Swal.fire("Error!","Error in loading Data!","error"); 37 | } 38 | ); 39 | } 40 | 41 | deleteQuiz(qId:any){ 42 | 43 | Swal.fire({ 44 | icon: "question", 45 | title:"Are you sure?", 46 | confirmButtonText:"Delete", 47 | showCancelButton: true, 48 | }).then((result)=>{ 49 | 50 | if (result.isConfirmed){ 51 | this._quiz.deleteQuiz(qId).subscribe( 52 | (data)=>{ 53 | this.quizzes=this.quizzes.filter((quiz)=>quiz.qId!=qId); 54 | Swal.fire("Success","Quiz deleted","success"); 55 | }, 56 | (error)=> { 57 | Swal.fire("Error","Error on deleting","error"); 58 | } 59 | ); 60 | } 61 | }); 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/controller/CategoryController.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.controller; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | import com.examenv.examserver.service.CategoryService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | @RestController 13 | @RequestMapping("/category") 14 | @CrossOrigin("*") 15 | public class CategoryController { 16 | 17 | @Autowired 18 | private CategoryService categoryService; 19 | 20 | //add category 21 | @PostMapping("/") 22 | public ResponseEntity addCategory(@RequestBody Category category){ 23 | Category category1 = this.categoryService.addCategory(category); 24 | return ResponseEntity.ok(category1); 25 | } 26 | 27 | 28 | //get category 29 | @GetMapping("/{categoryId}") 30 | public Category getCategory(@PathVariable("categoryId") Long categoryId){ 31 | return this.categoryService.getCategory(categoryId); 32 | } 33 | 34 | //get all categories 35 | @GetMapping("/") 36 | public ResponseEntity getCategories() { 37 | return ResponseEntity.ok(this.categoryService.getCategories()); 38 | } 39 | 40 | 41 | //update category 42 | @PutMapping("/") 43 | public Category updateCategory(@RequestBody Category category){ 44 | return this.categoryService.updateCategory(category); 45 | } 46 | 47 | //delete category 48 | @DeleteMapping("/{categoryId}") 49 | public void deleteCategory(@PathVariable("categoryId") Long categoryId){ 50 | this.categoryService.deleteCategory(categoryId); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/impl/QuestionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service.impl; 2 | 3 | import com.examenv.examserver.model.exam.Question; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | import com.examenv.examserver.repo.QuestionRepository; 6 | import com.examenv.examserver.service.QuestionService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | @Service 13 | public class QuestionServiceImpl implements QuestionService { 14 | 15 | @Autowired 16 | private QuestionRepository questionRepository; 17 | 18 | @Override 19 | public Question addQuestion(Question question) { 20 | return this.questionRepository.save(question); 21 | } 22 | 23 | @Override 24 | public Question updateQuestion(Question question) { 25 | return this.questionRepository.save(question); 26 | } 27 | 28 | @Override 29 | public Set getQuestion() { 30 | return new HashSet<>(this.questionRepository.findAll()); 31 | } 32 | 33 | @Override 34 | public Question getQuestion(Long questionId) { 35 | return this.questionRepository.findById(questionId).get(); 36 | } 37 | 38 | @Override 39 | public Set getQuestionsOfQuiz(Quiz quiz) { 40 | return this.questionRepository.findByQuiz(quiz); 41 | } 42 | 43 | @Override 44 | public void deleteQuestion(Long questionId) { 45 | Question question = new Question(); 46 | question.setQuestionId(questionId); 47 | this.questionRepository.delete(question); 48 | } 49 | 50 | @Override 51 | public Question get(Long questionsId) { 52 | return this.questionRepository.getOne(questionsId); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/impl/QuizServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service.impl; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | import com.examenv.examserver.repo.QuizRepository; 6 | import com.examenv.examserver.service.QuizService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Set; 13 | @Service 14 | public class QuizServiceImpl implements QuizService { 15 | 16 | @Autowired 17 | private QuizRepository quizRepository; 18 | 19 | @Override 20 | public Quiz addQuiz(Quiz quiz) { 21 | return this.quizRepository.save(quiz); 22 | } 23 | 24 | @Override 25 | public Quiz updateQuiz(Quiz quiz) { 26 | return this.quizRepository.save(quiz); 27 | } 28 | 29 | @Override 30 | public Set getQuizzes() { 31 | return new HashSet<>(this.quizRepository.findAll()); 32 | } 33 | 34 | @Override 35 | public Quiz getQuiz(Long quizId) { 36 | return this.quizRepository.findById(quizId).get(); 37 | } 38 | 39 | @Override 40 | public void deleteQuiz(Long quizId) { 41 | this.quizRepository.deleteById(quizId); 42 | } 43 | 44 | @Override 45 | public List getQuizzesOfCategory(Category category) { 46 | return this.quizRepository.findBycategory(category); 47 | } 48 | 49 | @Override 50 | public List getActiveQuizzes() { 51 | return this.quizRepository.findByActive(true); 52 | } 53 | 54 | @Override 55 | public List getActiveQuizzesOfCategory(Category category) { 56 | return this.quizRepository.findByCategoryAndActive(category,true); 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.service.impl; 2 | 3 | import com.examenv.examserver.helper.UserFoundException; 4 | import com.examenv.examserver.helper.UserNotFoundException; 5 | import com.examenv.examserver.model.User; 6 | import com.examenv.examserver.model.UserRole; 7 | import com.examenv.examserver.repo.RoleRepository; 8 | import com.examenv.examserver.repo.UserRepository; 9 | import com.examenv.examserver.service.UserService; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.Set; 14 | 15 | @Service 16 | public class UserServiceImpl implements UserService { 17 | 18 | @Autowired 19 | private UserRepository userRepository; 20 | 21 | @Autowired 22 | private RoleRepository roleRepository; 23 | 24 | 25 | //creating user 26 | @Override 27 | public User createUser(User user, Set userRoles) throws Exception { 28 | User local = this.userRepository.findByUsername(user.getUsername()); 29 | if (local != null){ 30 | System.out.println("User is already there!!"); 31 | throw new UserFoundException(); 32 | }else { 33 | //user create 34 | for (UserRole ur: userRoles){ 35 | roleRepository.save(ur.getRole()); 36 | } 37 | 38 | user.getUserRoles().addAll(userRoles); 39 | local = this.userRepository.save(user); 40 | } 41 | return local; 42 | } 43 | 44 | //Get user by username 45 | @Override 46 | public User getUser(String username) { 47 | return this.userRepository.findByUsername(username); 48 | } 49 | 50 | @Override 51 | public void deleteUser(Long userId) { 52 | this.userRepository.deleteById(userId); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/update-quiz/update-quiz.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | import { CategoryService } from 'src/app/services/category.service'; 4 | import { QuizService } from 'src/app/services/quiz.service'; 5 | import Swal from 'sweetalert2'; 6 | 7 | @Component({ 8 | selector: 'app-update-quiz', 9 | templateUrl: './update-quiz.component.html', 10 | styleUrls: ['./update-quiz.component.css'] 11 | }) 12 | export class UpdateQuizComponent implements OnInit { 13 | 14 | constructor(private _route:ActivatedRoute, private _quiz: QuizService, private _categories: CategoryService, private _router: Router) { } 15 | 16 | qId = 0; 17 | quiz= { 18 | title: '', 19 | description:'', 20 | maxMark: '', 21 | numberOfQuestions: '', 22 | active: true, 23 | category: { 24 | cId: '', 25 | } 26 | }; 27 | categories=[ 28 | { 29 | cId: "0", 30 | title: "default", 31 | } 32 | ]; 33 | 34 | ngOnInit(): void { 35 | this.qId = this._route.snapshot.params["qid"]; 36 | this._quiz.getQuiz(this.qId).subscribe( 37 | (data:any)=>{ 38 | this.quiz = data; 39 | console.log(data); 40 | }, 41 | (error)=>{ 42 | console.log(error); 43 | } 44 | ); 45 | 46 | this._categories.categories().subscribe( 47 | (data: any)=> { 48 | this.categories = data; 49 | }, 50 | (error)=>{ 51 | console.log(error); 52 | } 53 | ); 54 | } 55 | 56 | 57 | //update form submit 58 | public updateData(){ 59 | 60 | this._quiz.updateQuiz(this.quiz).subscribe( 61 | (data:any)=>{ 62 | Swal.fire("Success","Quiz Updated","success").then( 63 | (e)=>{ 64 | this._router.navigate(['/admin/quizzes']); 65 | } 66 | ); 67 | }, 68 | (error)=>{ 69 | Swal.fire("Error","Error when updating Data","error"); 70 | } 71 | ); 72 | 73 | 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /examenvfront/src/app/services/login.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Subject } from 'rxjs'; 4 | import baseUrl from './helper'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class LoginService { 10 | 11 | public loginStatusSubject = new Subject(); 12 | 13 | constructor(private http:HttpClient) { } 14 | 15 | //current user: that's logged in 16 | public getCurrentUser(){ 17 | return this.http.get(`${baseUrl}/current-user`); 18 | } 19 | 20 | //generate token 21 | 22 | public generateToken(loginData: any) { 23 | return this.http.post(`${baseUrl}/generate-token`,loginData); 24 | } 25 | 26 | //login useer: set token in localstorage 27 | public loginUser(token: any){ 28 | localStorage.setItem("token",token); 29 | 30 | return true; 31 | } 32 | 33 | //isLogin: user is logged in or not 34 | public isLoggedIn() { 35 | let tokenStr = localStorage.getItem("token"); 36 | if(tokenStr == undefined || tokenStr == '' || tokenStr == null){ 37 | return false; 38 | }else { 39 | return true; 40 | } 41 | } 42 | 43 | //logout: remove token from local storage 44 | public logout() { 45 | localStorage.removeItem("token"); 46 | localStorage.removeItem("user"); 47 | return true; 48 | } 49 | 50 | // get token 51 | public getToken() { 52 | return localStorage.getItem("token"); 53 | } 54 | 55 | // set userDetail 56 | public setUser(user: any) { 57 | localStorage.setItem("user", JSON.stringify(user)); 58 | } 59 | 60 | //getUser 61 | public getUser() { 62 | let userStr = localStorage.getItem("user"); 63 | if (userStr != null){ 64 | return JSON.parse(userStr); 65 | }else { 66 | this.logout(); 67 | return null; 68 | } 69 | } 70 | 71 | 72 | // get user role 73 | public getUserRole() { 74 | let user = this.getUser(); 75 | return user.authorities[0].authority; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-question/add-question.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | import { QuestionService } from 'src/app/services/question.service'; 4 | import Swal from 'sweetalert2'; 5 | 6 | @Component({ 7 | selector: 'app-add-question', 8 | templateUrl: './add-question.component.html', 9 | styleUrls: ['./add-question.component.css'] 10 | }) 11 | export class AddQuestionComponent implements OnInit { 12 | 13 | qId:any; 14 | qTitle:any; 15 | question={ 16 | quiz:{ 17 | qId:'' 18 | }, 19 | content:'', 20 | option1:'', 21 | option2:'', 22 | option3:'', 23 | option4:'', 24 | answer:'' 25 | }; 26 | 27 | 28 | constructor(private _route:ActivatedRoute, private _question: QuestionService) { } 29 | 30 | ngOnInit(): void { 31 | this.qId = this._route.snapshot.params["qid"]; 32 | this.qTitle = this._route.snapshot.params["title"]; 33 | this.question.quiz['qId'] = this.qId; 34 | } 35 | 36 | submitData(){ 37 | if(this.question.content.trim() == '' || this.question.content == null){ 38 | return; 39 | } 40 | if(this.question.option1.trim() == '' || this.question.option1 == null){ 41 | return; 42 | } 43 | if(this.question.option2.trim() == '' || this.question.option2 == null){ 44 | return; 45 | } 46 | if(this.question.answer.trim() == '' || this.question.answer == null){ 47 | return; 48 | } 49 | 50 | this._question.addQuestion(this.question).subscribe( 51 | (data:any)=>{ 52 | Swal.fire("Success","Question has been added.","success"); 53 | this.question.content = ''; 54 | this.question.option1 = ''; 55 | this.question.option2 = ''; 56 | this.question.option3 = ''; 57 | this.question.option4 = ''; 58 | this.question.answer = ''; 59 | }, 60 | (error)=>{ 61 | Swal.fire("Error","Error on adding question.","error"); 62 | } 63 | ); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/instructions/instructions.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 | 8 | Read the instructions on this page carefully 9 | 10 | 11 | One more step 12 | 13 | 14 | 15 |

{{quiz.title}}

16 |

{{quiz.description}}

17 | 18 |
19 |

Important Instructions

20 | 21 |
    22 |
  • This quiz is only for practice purpose.
  • 23 |
  • You have to submit the quiz before the time is over. ({{quiz.numberOfQuestions*2}} 24 | minutes)
  • 25 |
  • You can participate in the quiz unlimitedly.
  • 26 |
  • The are {{quiz.numberOfQuestions}} questions in this quiz.
  • 27 |
  • Each question worths {{quiz.maxMark / quiz.numberOfQuestions | number:'1.1-2'}} 28 | marks.
  • 29 |
  • All of the Quizzes are Multiple Choice Questions.
  • 30 |
31 | 32 | 33 |
34 |

Attempting Quiz

35 |
    36 |
  • Click Start Test button to start the quiz.
  • 37 |
  • The time will start the moment you click the Start Test button.
  • 38 |
  • You cannot resume this quiz, if interrupted due to any reason.
  • 39 |
  • Scroll down to move next question.
  • 40 |
  • Click on Submit Button on completion of the quiz.
  • 41 |
  • Report of the test is automatically generated in the form of PDF copy.
  • 42 |
43 | 44 |
45 | 46 | 47 | 48 |
49 |
50 |
51 |
52 |
-------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-quiz/add-quiz.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { MatSnackBar } from '@angular/material/snack-bar'; 3 | import { CategoryService } from 'src/app/services/category.service'; 4 | import { QuizService } from 'src/app/services/quiz.service'; 5 | import Swal from 'sweetalert2'; 6 | 7 | @Component({ 8 | selector: 'app-add-quiz', 9 | templateUrl: './add-quiz.component.html', 10 | styleUrls: ['./add-quiz.component.css'] 11 | }) 12 | export class AddQuizComponent implements OnInit { 13 | 14 | categories=[ 15 | { 16 | cId: "0", 17 | title: "default", 18 | } 19 | ]; 20 | 21 | quizData = { 22 | title: '', 23 | description:'', 24 | maxMark: '', 25 | numberOfQuestions: '', 26 | active: true, 27 | category: { 28 | cId: '', 29 | } 30 | }; 31 | 32 | constructor(private _cat:CategoryService, private _snack: MatSnackBar,private _quiz:QuizService) { } 33 | 34 | ngOnInit(): void { 35 | this._cat.categories().subscribe( 36 | (data:any)=> { 37 | this.categories = data; 38 | console.log(this.categories); 39 | }, 40 | (error)=> { 41 | console.log(error); 42 | Swal.fire("Error!","Error in loading data","error"); 43 | } 44 | ); 45 | } 46 | 47 | addQuiz(){ 48 | if (this.quizData.title.trim() == '' || this.quizData.title == null){ 49 | this._snack.open("Title Required","OK",{ 50 | duration: 2500 51 | }); 52 | } 53 | 54 | this._quiz.addQuiz(this.quizData).subscribe( 55 | (data: any)=> { 56 | Swal.fire("Succesfull","Quiz has been added","success"); 57 | this.quizData = { 58 | title: '', 59 | description:'', 60 | maxMark: '', 61 | numberOfQuestions: '', 62 | active: true, 63 | category: { 64 | cId: '', 65 | } 66 | }; 67 | }, 68 | (error)=>{ 69 | Swal.fire("Error","Error while adding the quiz","error"); 70 | } 71 | ); 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/ExamserverApplication.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver; 2 | 3 | import com.examenv.examserver.helper.UserFoundException; 4 | import com.examenv.examserver.model.Role; 5 | import com.examenv.examserver.model.User; 6 | import com.examenv.examserver.model.UserRole; 7 | import com.examenv.examserver.service.UserService; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.CommandLineRunner; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | 14 | import java.util.HashSet; 15 | import java.util.Set; 16 | 17 | @SpringBootApplication 18 | public class ExamserverApplication implements CommandLineRunner { 19 | 20 | @Autowired 21 | private UserService userService; 22 | 23 | @Autowired 24 | private BCryptPasswordEncoder bCryptPasswordEncoder; 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(ExamserverApplication.class, args); 28 | } 29 | 30 | @Override 31 | public void run(String... args) throws Exception { 32 | /* 33 | try { 34 | System.out.println("starting code"); 35 | 36 | User user = new User(); 37 | 38 | user.setFirstName("Berk"); 39 | user.setLastName("Beleli"); 40 | user.setUsername("berkbeleli"); 41 | user.setPassword(this.bCryptPasswordEncoder.encode("1234")); 42 | user.setEmail("berk@mail.com"); 43 | user.setProfile("default.png"); 44 | 45 | Role role1 = new Role(); 46 | role1.setRoleId(55l); 47 | role1.setRoleName("ADMIN"); 48 | 49 | Set userRoleSet = new HashSet<>(); 50 | UserRole userRole = new UserRole(); 51 | userRole.setRole(role1); 52 | userRole.setUser(user); 53 | 54 | userRoleSet.add(userRole); 55 | User user1 = this.userService.createUser(user, userRoleSet); 56 | System.out.println(user1.getUsername()); 57 | }catch (UserFoundException e){ 58 | e.printStackTrace(); 59 | } 60 | 61 | */ 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/update-quiz/update-quiz.component.html: -------------------------------------------------------------------------------- 1 | 2 |

Update Quiz

3 |
4 |
5 |
6 |
7 | 8 | Enter Title 9 | 10 | 11 | 12 | 13 | Enter Description 14 | 15 | 16 | 17 |
18 |
19 | 20 | 21 | Maximum Mark 22 | 23 | 24 | 25 |
26 |
27 | 28 | Number of Questions 29 | 30 | 31 |
32 |
33 | 34 | 35 | Publish Status 36 | 37 |
38 | 39 | Categories 40 | 41 | 42 | {{cat["title"]}} 43 | 44 | 45 | 46 | 47 |
48 | 49 |
50 |
51 |
52 |
53 |
54 |
-------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-quiz/add-quiz.component.html: -------------------------------------------------------------------------------- 1 | 2 |

Add New Quiz

3 |
4 |
5 |
6 | 7 |
8 | 9 | 10 | 11 | Enter Title 12 | 13 | 14 | 15 | 16 | Enter Description 17 | 18 | 19 | 20 |
21 |
22 | 23 | 24 | Maximum Mark 25 | 26 | 27 | 28 |
29 |
30 | 31 | Number of Questions 32 | 33 | 34 |
35 |
36 | 37 | 38 | Publish Status 39 | 40 |
41 | 42 | Categories 43 | 44 | 45 | {{cat["title"]}} 46 | 47 | 48 | 49 | 50 |
51 | 52 |
53 |
54 |
55 |
56 |
57 |
58 | -------------------------------------------------------------------------------- /examserver/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.5 9 | 10 | 11 | com.examenv 12 | examserver 13 | 0.0.1-SNAPSHOT 14 | examserver 15 | Backend code for Exam Environment 16 | 17 | 19 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-jpa 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-security 32 | 33 | 34 | 35 | com.mysql 36 | mysql-connector-j 37 | runtime 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-test 42 | test 43 | 44 | 45 | 46 | io.jsonwebtoken 47 | jjwt 48 | 0.9.1 49 | 50 | 51 | 52 | javax.xml.bind 53 | jaxb-api 54 | 2.3.1 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/view-quiz-questions/view-quiz-questions.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { MatSnackBar } from '@angular/material/snack-bar'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { QuestionService } from 'src/app/services/question.service'; 5 | import Swal from 'sweetalert2'; 6 | 7 | @Component({ 8 | selector: 'app-view-quiz-questions', 9 | templateUrl: './view-quiz-questions.component.html', 10 | styleUrls: ['./view-quiz-questions.component.css'] 11 | }) 12 | export class ViewQuizQuestionsComponent implements OnInit { 13 | qId:any; 14 | qTitle:any; 15 | questions = [ 16 | { 17 | questionId: '', 18 | content:'', 19 | option1:'', 20 | option2:'', 21 | option3:'', 22 | option4:'', 23 | answer:'', 24 | } 25 | ]; 26 | 27 | constructor(private _route:ActivatedRoute, private _question: QuestionService,private _snack:MatSnackBar) { } 28 | 29 | ngOnInit(): void { 30 | this.qId = this._route.snapshot.params["qid"]; 31 | this.qTitle = this._route.snapshot.params["title"]; 32 | this._question.getQuestionsOfQuiz(this.qId).subscribe( 33 | (data:any)=>{ 34 | console.log(data); 35 | this.questions = data; 36 | }, 37 | (error)=>{ 38 | console.log(error); 39 | } 40 | ); 41 | } 42 | 43 | deleteQuestion(questionId:any){ 44 | Swal.fire({ 45 | icon: 'info', 46 | showCancelButton: true, 47 | confirmButtonText: 'Delete', 48 | title: 'Do you really want to delete this question?', 49 | }).then( 50 | (result)=>{ 51 | if(result.isConfirmed){ 52 | this._question.deleteQuestion(questionId).subscribe( 53 | (data)=>{ 54 | this._snack.open("Question Deleted","OK",{ 55 | duration: 2500, 56 | }); 57 | this.questions = this.questions.filter((q)=>q.questionId != questionId); 58 | }, 59 | (error)=>{ 60 | this._snack.open("Error on deleting question","OK",{ 61 | duration:2500 62 | }); 63 | } 64 | ); 65 | } 66 | } 67 | ); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/config/JwtUtils.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.config; 2 | 3 | import io.jsonwebtoken.Claims; 4 | import io.jsonwebtoken.Jwts; 5 | import io.jsonwebtoken.SignatureAlgorithm; 6 | import org.springframework.security.core.userdetails.UserDetails; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.Date; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.function.Function; 14 | 15 | @Component 16 | public class JwtUtils { 17 | private String SECRET_KEY = "examenvironment"; 18 | 19 | public String extractUsername(String token) { 20 | return extractClaim(token, Claims::getSubject); 21 | } 22 | 23 | public Date extractExpiration(String token) { 24 | return extractClaim(token, Claims::getExpiration); 25 | } 26 | 27 | public T extractClaim(String token, Function claimsResolver) { 28 | final Claims claims = extractAllClaims(token); 29 | return claimsResolver.apply(claims); 30 | } 31 | private Claims extractAllClaims(String token) { 32 | return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); 33 | } 34 | 35 | private Boolean isTokenExpired(String token) { 36 | return extractExpiration(token).before(new Date()); 37 | } 38 | 39 | public String generateToken(UserDetails userDetails) { 40 | Map claims = new HashMap<>(); 41 | return createToken(claims, userDetails.getUsername()); 42 | } 43 | 44 | private String createToken(Map claims, String subject) { 45 | 46 | return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) 47 | .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) 48 | .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact(); 49 | } 50 | 51 | public Boolean validateToken(String token, UserDetails userDetails) { 52 | final String username = extractUsername(token); 53 | return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/controller/QuizController.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.controller; 2 | 3 | import com.examenv.examserver.model.exam.Category; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | import com.examenv.examserver.service.QuizService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import java.util.List; 11 | 12 | @RestController 13 | @CrossOrigin("*") 14 | @RequestMapping("/quiz") 15 | public class QuizController { 16 | 17 | @Autowired 18 | private QuizService quizService; 19 | 20 | //add quiz 21 | @PostMapping("/") 22 | public ResponseEntity add(@RequestBody Quiz quiz){ 23 | return ResponseEntity.ok(this.quizService.addQuiz(quiz)); 24 | } 25 | 26 | //update quiz 27 | @PutMapping("/") 28 | public ResponseEntity update(@RequestBody Quiz quiz){ 29 | return ResponseEntity.ok(this.quizService.updateQuiz(quiz)); 30 | } 31 | 32 | //get quizzess 33 | @GetMapping("/") 34 | public ResponseEntity quizzes() { 35 | return ResponseEntity.ok(this.quizService.getQuizzes()); 36 | } 37 | 38 | //get single quiz 39 | @GetMapping("/{qid}") 40 | public Quiz quiz(@PathVariable("qid") Long qid){ 41 | return this.quizService.getQuiz(qid); 42 | } 43 | 44 | //delete quiz 45 | @DeleteMapping("/{qid}") 46 | public void delete(@PathVariable("qid") Long qid){ 47 | this.quizService.deleteQuiz(qid); 48 | } 49 | 50 | 51 | @GetMapping("/category/{cId}") 52 | public List getQuizzesOfCategory(@PathVariable("cId") Long cId){ 53 | Category category = new Category(); 54 | category.setcId(cId); 55 | return this.quizService.getQuizzesOfCategory(category); 56 | } 57 | 58 | //get active quizzes 59 | @GetMapping("/active") 60 | public List getActiveQuizzes(){ 61 | return this.quizService.getActiveQuizzes(); 62 | } 63 | 64 | //get active quizzes by category 65 | @GetMapping("/category/active/{cId}") 66 | public List getActiveQuizzes(@PathVariable("cId") Long cId ){ 67 | Category category = new Category(); 68 | category.setcId(cId); 69 | return this.quizService.getActiveQuizzesOfCategory(category); 70 | } 71 | 72 | 73 | 74 | } -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/exam/Quiz.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model.exam; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import javax.persistence.*; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | @Entity 10 | public class Quiz { 11 | @Id 12 | @GeneratedValue(strategy = GenerationType.AUTO) 13 | private Long qId; 14 | private String title; 15 | @Column(length = 5000) 16 | private String description; 17 | 18 | private String maxMark; 19 | private String numberOfQuestions; 20 | 21 | private boolean active = false; 22 | 23 | @ManyToOne(fetch = FetchType.EAGER) 24 | private Category category; 25 | 26 | @OneToMany(mappedBy = "quiz", fetch = FetchType.LAZY, cascade = CascadeType.ALL) 27 | @JsonIgnore 28 | private Set questions = new HashSet<>(); 29 | 30 | 31 | public Quiz() { 32 | } 33 | 34 | public Long getqId() { 35 | return qId; 36 | } 37 | 38 | public void setqId(Long qId) { 39 | this.qId = qId; 40 | } 41 | 42 | public String getTitle() { 43 | return title; 44 | } 45 | 46 | public void setTitle(String title) { 47 | this.title = title; 48 | } 49 | 50 | public String getDescription() { 51 | return description; 52 | } 53 | 54 | public void setDescription(String description) { 55 | this.description = description; 56 | } 57 | 58 | public String getMaxMark() { 59 | return maxMark; 60 | } 61 | 62 | public void setMaxMark(String maxMark) { 63 | this.maxMark = maxMark; 64 | } 65 | 66 | public String getNumberOfQuestions() { 67 | return numberOfQuestions; 68 | } 69 | 70 | public void setNumberOfQuestions(String numberOfQuestions) { 71 | this.numberOfQuestions = numberOfQuestions; 72 | } 73 | 74 | public boolean isActive() { 75 | return active; 76 | } 77 | 78 | public void setActive(boolean active) { 79 | this.active = active; 80 | } 81 | 82 | public Category getCategory() { 83 | return category; 84 | } 85 | 86 | public void setCategory(Category category) { 87 | this.category = category; 88 | } 89 | 90 | public Set getQuestions() { 91 | return questions; 92 | } 93 | 94 | public void setQuestions(Set questions) { 95 | this.questions = questions; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.controller; 2 | 3 | import com.examenv.examserver.helper.UserFoundException; 4 | import com.examenv.examserver.helper.UserNotFoundException; 5 | import com.examenv.examserver.model.Role; 6 | import com.examenv.examserver.model.User; 7 | import com.examenv.examserver.model.UserRole; 8 | import com.examenv.examserver.service.UserService; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import java.nio.file.attribute.UserPrincipalNotFoundException; 16 | import java.util.HashSet; 17 | import java.util.Set; 18 | 19 | @RestController 20 | @RequestMapping("/user") 21 | @CrossOrigin("*") 22 | public class UserController { 23 | 24 | @Autowired 25 | private UserService userService; 26 | 27 | @Autowired 28 | private BCryptPasswordEncoder bCryptPasswordEncoder; 29 | 30 | //creating user 31 | @PostMapping("/") 32 | public User createUser(@RequestBody User user) throws Exception { 33 | user.setProfile("default.png"); 34 | //encoding password with bcryptpasswordencoder 35 | 36 | user.setPassword(this.bCryptPasswordEncoder.encode(user.getPassword())); 37 | 38 | Set roles = new HashSet<>(); 39 | 40 | Role role1 = new Role(); 41 | role1.setRoleId(45l); 42 | role1.setRoleName("NORMAL"); 43 | 44 | UserRole userRole = new UserRole(); 45 | userRole.setRole(role1); 46 | userRole.setUser(user); 47 | roles.add(userRole); 48 | 49 | return this.userService.createUser(user, roles); 50 | } 51 | 52 | @GetMapping("{username}") 53 | public User getUser(@PathVariable("username") String username ){ 54 | return this.userService.getUser(username); 55 | } 56 | 57 | //delete the user by id 58 | @DeleteMapping("/{userId}") 59 | public void deleteUser(@PathVariable("userId") Long userId) { 60 | this.userService.deleteUser(userId); 61 | } 62 | 63 | @ExceptionHandler(UserFoundException.class) 64 | public ResponseEntity exceptionHandler(UserFoundException ex){ 65 | return new ResponseEntity<>(new UserFoundException(), HttpStatus.BAD_REQUEST); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /examenvfront/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { MatSnackBar } from '@angular/material/snack-bar'; 3 | import { Router } from '@angular/router'; 4 | import { LoginService } from 'src/app/services/login.service'; 5 | 6 | @Component({ 7 | selector: 'app-login', 8 | templateUrl: './login.component.html', 9 | styleUrls: ['./login.component.css'] 10 | }) 11 | export class LoginComponent implements OnInit { 12 | 13 | loginData={ 14 | username: '', 15 | password: '', 16 | }; 17 | 18 | constructor(private snack:MatSnackBar, private login: LoginService, private router: Router) { } 19 | 20 | ngOnInit(): void { 21 | } 22 | 23 | formSubmit() { 24 | if (this.loginData.username.trim() == '' || this.loginData.username == null){ 25 | this.snack.open("Username is require!d", 'OK', { 26 | duration: 2500 27 | }); 28 | return; 29 | } 30 | if (this.loginData.password.trim() == '' || this.loginData.password == null){ 31 | this.snack.open("Password is require!d", 'OK', { 32 | duration: 2500 33 | }); 34 | return; 35 | } 36 | 37 | 38 | //Request from server to generate token 39 | this.login.generateToken(this.loginData).subscribe( 40 | (data: any) => { 41 | console.log("success"); 42 | console.log(data); 43 | 44 | //login... 45 | this.login.loginUser(data.token); 46 | this.login.getCurrentUser().subscribe( 47 | (user:any)=> { 48 | this.login.setUser(user); 49 | console.log(user); 50 | // redirect... admin: admin-dashboard 51 | // redirect... normal: normal-dashboard 52 | if (this.login.getUserRole() == "ADMIN"){ 53 | //window.location.href = '/admin'; 54 | this.router.navigate(['admin']); 55 | this.login.loginStatusSubject.next(true); 56 | 57 | }else if (this.login.getUserRole() == "NORMAL"){ 58 | //window.location.href = '/user-dashboard'; 59 | this.router.navigate(['user-dashboard/0']); 60 | this.login.loginStatusSubject.next(true); 61 | }else { 62 | this.login.logout(); 63 | } 64 | } 65 | ); 66 | 67 | 68 | }, 69 | (error)=> { 70 | console.log("Error"); 71 | console.log(error); 72 | this.snack.open("Invalid Details! Try again" ,"OK",{ 73 | duration: 2500, 74 | }) 75 | } 76 | ); 77 | 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/exam/Question.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model.exam; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | import javax.persistence.*; 7 | 8 | @Entity 9 | public class Question { 10 | @Id 11 | @GeneratedValue(strategy = GenerationType.AUTO) 12 | private Long questionId; 13 | @Column(length = 5000) 14 | private String content; 15 | 16 | private String image; 17 | private String option1; 18 | private String option2; 19 | private String option3; 20 | private String option4; 21 | 22 | private String answer; 23 | 24 | @Transient 25 | private String givenAnswer; 26 | 27 | @ManyToOne(fetch = FetchType.EAGER) 28 | private Quiz quiz; 29 | 30 | public Question() { 31 | } 32 | 33 | public Long getQuestionId() { 34 | return questionId; 35 | } 36 | 37 | public void setQuestionId(Long questionId) { 38 | this.questionId = questionId; 39 | } 40 | 41 | public String getContent() { 42 | return content; 43 | } 44 | 45 | public void setContent(String content) { 46 | this.content = content; 47 | } 48 | 49 | public String getImage() { 50 | return image; 51 | } 52 | 53 | public void setImage(String image) { 54 | this.image = image; 55 | } 56 | 57 | public String getOption1() { 58 | return option1; 59 | } 60 | 61 | public void setOption1(String option1) { 62 | this.option1 = option1; 63 | } 64 | 65 | public String getOption2() { 66 | return option2; 67 | } 68 | 69 | public void setOption2(String option2) { 70 | this.option2 = option2; 71 | } 72 | 73 | public String getOption3() { 74 | return option3; 75 | } 76 | 77 | public void setOption3(String option3) { 78 | this.option3 = option3; 79 | } 80 | 81 | public String getOption4() { 82 | return option4; 83 | } 84 | 85 | public void setOption4(String option4) { 86 | this.option4 = option4; 87 | } 88 | 89 | 90 | public String getAnswer() { 91 | return answer; 92 | } 93 | 94 | 95 | public void setAnswer(String answer) { 96 | this.answer = answer; 97 | } 98 | 99 | public Quiz getQuiz() { 100 | return quiz; 101 | } 102 | 103 | public void setQuiz(Quiz quiz) { 104 | this.quiz = quiz; 105 | } 106 | 107 | public String getGivenAnswer() { 108 | return givenAnswer; 109 | } 110 | 111 | public void setGivenAnswer(String givenAnswer) { 112 | this.givenAnswer = givenAnswer; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/admin/add-question/add-question.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Adding Question to {{qTitle}}

5 | 6 | 7 | 8 | 9 | Enter the details of the new question 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | Enter question content 18 | 19 | 20 | 21 |
22 |
23 | 24 | Enter Option 1 25 | 26 | 27 |
28 |
29 | 30 | Enter Option 2 31 | 32 | 33 |
34 |
35 | 36 |
37 |
38 | 39 | Enter Option 3 40 | 41 | 42 |
43 |
44 | 45 | Enter Option 4 46 | 47 | 48 |
49 | 50 |
51 | 52 | 53 | Select Answer 54 | 55 | {{question.option1}} 56 | {{question.option2}} 57 | {{question.option3}} 58 | {{question.option4}} 59 | 60 | 61 | 62 |
63 | 64 |
65 |
66 |
67 |
68 |
69 |
70 |
-------------------------------------------------------------------------------- /examenvfront/src/app/pages/signup/signup.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 | 8 |
9 | 10 |
11 |

Register

12 | 13 |
14 | 15 | 16 | 17 | Username 18 | 23 | Username must be unique 24 | 25 | 26 | 27 | 28 | Password 29 | 34 | 35 | 36 | 37 | 38 | 39 | First Name 40 | 45 | 46 | 47 | 48 | 49 | Last Name 50 | 55 | 56 | 57 | 58 | 59 | E-mail 60 | 65 | 66 | 67 | 68 | 69 | Phone Number 70 | 75 | 76 | 77 |
78 | 79 | 80 |
81 |
82 | 83 | 84 |
85 |
86 | 87 |
88 |
89 | 90 |
-------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/controller/AuthenticateController.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.controller; 2 | 3 | import com.examenv.examserver.config.JwtUtils; 4 | import com.examenv.examserver.helper.UserNotFoundException; 5 | import com.examenv.examserver.model.JwtRequest; 6 | import com.examenv.examserver.model.JwtResponse; 7 | import com.examenv.examserver.model.User; 8 | import com.examenv.examserver.service.impl.UserDetailsServiceImpl; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.ResponseEntity; 11 | import org.springframework.security.authentication.AuthenticationManager; 12 | import org.springframework.security.authentication.BadCredentialsException; 13 | import org.springframework.security.authentication.DisabledException; 14 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 15 | import org.springframework.security.core.userdetails.UserDetails; 16 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import java.security.Principal; 20 | 21 | @RestController 22 | @CrossOrigin("*") 23 | public class AuthenticateController { 24 | 25 | @Autowired 26 | private AuthenticationManager authenticationManager; 27 | 28 | @Autowired 29 | private UserDetailsServiceImpl userDetailsService; 30 | 31 | @Autowired 32 | private JwtUtils jwtUtils; 33 | 34 | //generate token 35 | @PostMapping("/generate-token") 36 | public ResponseEntity generateToken(@RequestBody JwtRequest jwtRequest) throws Exception { 37 | 38 | try { 39 | 40 | authenticate(jwtRequest.getUsername(),jwtRequest.getPassword()); 41 | 42 | }catch (UserNotFoundException e){ 43 | e.printStackTrace(); 44 | throw new Exception("User not found"); 45 | } 46 | 47 | ///////authenticate 48 | 49 | UserDetails userDetails = this.userDetailsService.loadUserByUsername(jwtRequest.getUsername()); 50 | 51 | String token = this.jwtUtils.generateToken(userDetails); 52 | return ResponseEntity.ok(new JwtResponse(token)); 53 | } 54 | 55 | 56 | 57 | private void authenticate(String username, String password) throws Exception { 58 | 59 | try { 60 | 61 | authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username,password)); 62 | }catch (DisabledException e){ 63 | throw new Exception("User Disabled" + e.getMessage()); 64 | }catch (BadCredentialsException e){ 65 | 66 | throw new Exception("Incalid Credentials" + e.getMessage()); 67 | } 68 | } 69 | 70 | //Rturn details of current user 71 | @GetMapping("/current-user") 72 | public User getCurrentUser(Principal principal){ 73 | return ((User)this.userDetailsService.loadUserByUsername(principal.getName())); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/config/MySecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.config; 2 | 3 | import com.examenv.examserver.service.impl.UserDetailsServiceImpl; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.http.HttpMethod; 8 | import org.springframework.security.authentication.AuthenticationManager; 9 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 10 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 11 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 12 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 13 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 14 | import org.springframework.security.config.http.SessionCreationPolicy; 15 | import org.springframework.security.core.userdetails.UserDetailsService; 16 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 17 | import org.springframework.security.crypto.password.NoOpPasswordEncoder; 18 | import org.springframework.security.crypto.password.PasswordEncoder; 19 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 20 | 21 | @EnableWebSecurity 22 | @Configuration 23 | @EnableGlobalMethodSecurity(prePostEnabled = true) 24 | public class MySecurityConfig extends WebSecurityConfigurerAdapter { 25 | 26 | @Autowired 27 | private JwtAuthenticationEntryPoint unauthorizedHandler; 28 | @Autowired 29 | private JwtAuthenticationFilter jwtAuthenticationFilter; 30 | @Autowired 31 | private UserDetailsServiceImpl userDetailsServiceImpl; 32 | 33 | @Override 34 | @Bean 35 | public AuthenticationManager authenticationManagerBean() throws Exception { 36 | return super.authenticationManagerBean(); 37 | } 38 | 39 | @Bean 40 | public BCryptPasswordEncoder passwordEncoder() { 41 | 42 | return new BCryptPasswordEncoder(); 43 | } 44 | @Override 45 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 46 | auth.userDetailsService(this.userDetailsServiceImpl).passwordEncoder(passwordEncoder()); 47 | } 48 | 49 | @Override 50 | protected void configure(HttpSecurity http) throws Exception { 51 | http 52 | .csrf() 53 | .disable() 54 | .cors() 55 | .disable() 56 | .authorizeRequests() 57 | .antMatchers("/generate-token","/user/").permitAll() 58 | .antMatchers(HttpMethod.OPTIONS).permitAll() 59 | .anyRequest().authenticated() 60 | .and() 61 | .exceptionHandling().authenticationEntryPoint(unauthorizedHandler) 62 | .and() 63 | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); 64 | 65 | http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/config/JwtAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.config; 2 | 3 | import com.examenv.examserver.service.impl.UserDetailsServiceImpl; 4 | import io.jsonwebtoken.ExpiredJwtException; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 7 | import org.springframework.security.core.context.SecurityContextHolder; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.core.userdetails.UserDetailsService; 10 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 11 | import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.web.filter.OncePerRequestFilter; 14 | 15 | import javax.servlet.FilterChain; 16 | import javax.servlet.ServletException; 17 | import javax.servlet.http.HttpServletRequest; 18 | import javax.servlet.http.HttpServletResponse; 19 | import java.io.IOException; 20 | import java.rmi.server.ExportException; 21 | 22 | @Component 23 | public class JwtAuthenticationFilter extends OncePerRequestFilter { 24 | 25 | @Autowired 26 | private UserDetailsServiceImpl userDetailsService; 27 | 28 | @Autowired 29 | private JwtUtils jwtUtil; 30 | 31 | @Override 32 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 33 | 34 | final String requestTokenHeader = request.getHeader("Authorization"); 35 | System.out.println(requestTokenHeader); 36 | String username = null; 37 | String jwtToken = null; 38 | 39 | if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) { 40 | //yes 41 | jwtToken=requestTokenHeader.substring(7); 42 | try { 43 | username = this.jwtUtil.extractUsername(jwtToken); 44 | }catch (ExpiredJwtException e){ 45 | e.printStackTrace(); 46 | System.out.println("Jwt Token has expired"); 47 | }catch (Exception e){ 48 | e.printStackTrace(); 49 | System.out.println("error"); 50 | } 51 | 52 | }else { 53 | System.out.println("Invalid Token, not started with bearer string."); 54 | } 55 | //validated 56 | if (username != null && SecurityContextHolder.getContext().getAuthentication() == null){ 57 | final UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); 58 | if (this.jwtUtil.validateToken(jwtToken,userDetails)){ 59 | // token is valid 60 | UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities()); 61 | usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); 62 | SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); 63 | } 64 | }else { 65 | System.out.println("Token is not valid"); 66 | } 67 | 68 | filterChain.doFilter(request,response); 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/start/start.component.ts: -------------------------------------------------------------------------------- 1 | import { LocationStrategy } from '@angular/common'; 2 | import { Component, OnInit } from '@angular/core'; 3 | import { ActivatedRoute } from '@angular/router'; 4 | import { QuestionService } from 'src/app/services/question.service'; 5 | import Swal from 'sweetalert2'; 6 | 7 | @Component({ 8 | selector: 'app-start', 9 | templateUrl: './start.component.html', 10 | styleUrls: ['./start.component.css'] 11 | }) 12 | export class StartComponent implements OnInit { 13 | 14 | qId:any; 15 | questions:any; 16 | 17 | marksGained=0; 18 | correctAnswers = 0; 19 | attempted = 0; 20 | 21 | isSubmit = false; 22 | 23 | timer:any; 24 | 25 | constructor(private locationSt: LocationStrategy, private _router: ActivatedRoute, private _question: QuestionService) { } 26 | 27 | ngOnInit(): void { 28 | this.preventBackButton(); 29 | this.qId = this._router.snapshot.params["qid"]; 30 | this.loadQuestions(); 31 | } 32 | 33 | loadQuestions() { 34 | this._question.getQuestionsOfQuizForTest(this.qId).subscribe( 35 | (data:any)=>{ 36 | this.questions = data; 37 | this.timer = this.questions.length * 2 * 60; 38 | this.questions.forEach( 39 | (q:any)=>{ 40 | q['givenAnswer'] = ''; 41 | }, 42 | ); 43 | console.log(this.questions); 44 | this.startTimer(); 45 | }, 46 | (error)=>{ 47 | Swal.fire("Error","Error in loading questions of quiz","error"); 48 | } 49 | ); 50 | } 51 | 52 | preventBackButton(){ 53 | history.pushState(null,'',location.href); 54 | this.locationSt.onPopState( 55 | ()=>{ 56 | history.pushState(null,'',location.href); 57 | } 58 | ); 59 | } 60 | 61 | submitQuiz(){ 62 | Swal.fire( 63 | { 64 | title: 'Do you want to submit the quiz?', 65 | showCancelButton: true, 66 | confirmButtonText: 'Submit', 67 | icon: 'info' 68 | } 69 | ).then( 70 | (result)=>{ 71 | if(result.isConfirmed){ 72 | this.evalQuiz(); 73 | } 74 | } 75 | ); 76 | } 77 | 78 | startTimer(){ 79 | let t = window.setInterval(()=>{ 80 | if(this.timer <= 0){ 81 | this.evalQuiz(); 82 | clearInterval(t); 83 | }else{ 84 | this.timer--; 85 | } 86 | },1000); 87 | } 88 | 89 | getFormattedTime(){ 90 | let mm = Math.floor(this.timer/60); 91 | let ss = this.timer - mm * 60; 92 | return `${mm} min : ${ss} sec`; 93 | } 94 | 95 | evalQuiz(){ 96 | this._question.evaluateQuiz(this.questions).subscribe( 97 | (data:any)=>{ 98 | this.correctAnswers = data.correctAnswers; 99 | this.attempted = data.attempted; 100 | this.marksGained = data.marksGained; 101 | this.isSubmit = true; 102 | }, 103 | (error)=>{ 104 | console.log(error); 105 | } 106 | ); 107 | /* 108 | this.isSubmit = true; 109 | this.questions.forEach( 110 | (q:any)=>{ 111 | 112 | if(q.givenAnswer == q.answer){ 113 | this.correctAnswers++; 114 | let markSingle = this.questions[0].quiz.maxMark / this.questions.length; 115 | this.marksGained += markSingle; 116 | } 117 | if(q.givenAnswer.trim()!=''){ 118 | this.attempted++; 119 | } 120 | } 121 | ); 122 | */ 123 | 124 | } 125 | 126 | printPage(){ 127 | window.print(); 128 | } 129 | 130 | 131 | } 132 | -------------------------------------------------------------------------------- /examenvfront/src/app/pages/user/start/start.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 |

Instructions

8 |
    9 |
  • Don't refresh this page
  • 10 |
  • Don't switch tabs
  • 11 |
  • Don't minimize the window
  • 12 |
13 |
14 |
15 |
16 |
17 | 18 |

On going Quiz {{questions[0].quiz.title}}

19 |
20 | 21 | 22 | 23 | 24 |

25 | Q{{i+1}}) 26 | 27 |

28 | 29 | 30 |
31 | 32 |
33 |
34 | {{quest.option1}} 36 |
37 |
38 | {{quest.option2}} 39 |
40 |
41 | 42 |
43 |
44 | {{quest.option3}} 45 |
46 |
47 | {{quest.option4}} 48 |
49 |
50 | 51 |
52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 |
60 | 61 | 62 | 63 | Progress 64 | 65 | 66 | Quiz will automatically submitted when the timer reaches to the end. 67 | 68 | 69 | 70 |

{{getFormattedTime()}}

71 | 72 |
73 |
74 |
75 |
76 |
77 |
78 | 79 |
80 |
81 |
82 | 83 | 84 | 85 | Quiz Result 86 | 87 | 88 | 89 |

Your Mark: {{ marksGained | number:'1.1-2'}}

90 |

Correct Answers: {{ correctAnswers }}

91 |

Number of Solved Questions: {{ attempted }}

92 |
93 | 94 | 95 | 96 | 97 |
98 |
99 |
100 |
-------------------------------------------------------------------------------- /examenvfront/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "examenvfront": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/examenvfront", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 27 | "src/styles.css", 28 | "./node_modules/bootstrap-grid-only-css/dist/css/bootstrap-grid.min.css" 29 | ], 30 | "scripts": [] 31 | }, 32 | "configurations": { 33 | "production": { 34 | "budgets": [ 35 | { 36 | "type": "initial", 37 | "maximumWarning": "500kb", 38 | "maximumError": "1mb" 39 | }, 40 | { 41 | "type": "anyComponentStyle", 42 | "maximumWarning": "2kb", 43 | "maximumError": "4kb" 44 | } 45 | ], 46 | "fileReplacements": [ 47 | { 48 | "replace": "src/environments/environment.ts", 49 | "with": "src/environments/environment.prod.ts" 50 | } 51 | ], 52 | "outputHashing": "all" 53 | }, 54 | "development": { 55 | "buildOptimizer": false, 56 | "optimization": false, 57 | "vendorChunk": true, 58 | "extractLicenses": false, 59 | "sourceMap": true, 60 | "namedChunks": true 61 | } 62 | }, 63 | "defaultConfiguration": "production" 64 | }, 65 | "serve": { 66 | "builder": "@angular-devkit/build-angular:dev-server", 67 | "configurations": { 68 | "production": { 69 | "browserTarget": "examenvfront:build:production" 70 | }, 71 | "development": { 72 | "browserTarget": "examenvfront:build:development" 73 | } 74 | }, 75 | "defaultConfiguration": "development" 76 | }, 77 | "extract-i18n": { 78 | "builder": "@angular-devkit/build-angular:extract-i18n", 79 | "options": { 80 | "browserTarget": "examenvfront:build" 81 | } 82 | }, 83 | "test": { 84 | "builder": "@angular-devkit/build-angular:karma", 85 | "options": { 86 | "main": "src/test.ts", 87 | "polyfills": "src/polyfills.ts", 88 | "tsConfig": "tsconfig.spec.json", 89 | "karmaConfig": "karma.conf.js", 90 | "assets": [ 91 | "src/favicon.ico", 92 | "src/assets" 93 | ], 94 | "styles": [ 95 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 96 | "src/styles.css" 97 | ], 98 | "scripts": [] 99 | } 100 | } 101 | } 102 | } 103 | }, 104 | "cli": { 105 | "analytics": false 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /examenvfront/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AddCategoryComponent } from './pages/admin/add-category/add-category.component'; 4 | import { AddQuestionComponent } from './pages/admin/add-question/add-question.component'; 5 | import { AddQuizComponent } from './pages/admin/add-quiz/add-quiz.component'; 6 | import { DashboardComponent } from './pages/admin/dashboard/dashboard.component'; 7 | import { UpdateQuizComponent } from './pages/admin/update-quiz/update-quiz.component'; 8 | import { ViewCategoriesComponent } from './pages/admin/view-categories/view-categories.component'; 9 | import { ViewQuizQuestionsComponent } from './pages/admin/view-quiz-questions/view-quiz-questions.component'; 10 | import { ViewQuizzesComponent } from './pages/admin/view-quizzes/view-quizzes.component'; 11 | import { WelcomeComponent } from './pages/admin/welcome/welcome.component'; 12 | import { HomeComponent } from './pages/home/home.component'; 13 | import { LoginComponent } from './pages/login/login.component'; 14 | import { ProfileComponent } from './pages/profile/profile.component'; 15 | import { SignupComponent } from './pages/signup/signup.component'; 16 | import { InstructionsComponent } from './pages/user/instructions/instructions.component'; 17 | import { LoadQuizComponent } from './pages/user/load-quiz/load-quiz.component'; 18 | import { StartComponent } from './pages/user/start/start.component'; 19 | import { UserDashboardComponent } from './pages/user/user-dashboard/user-dashboard.component'; 20 | import { AdminGuard } from './services/admin.guard'; 21 | import { NormalGuard } from './services/normal.guard'; 22 | 23 | const routes: Routes = [ 24 | { 25 | path: '', 26 | component: HomeComponent, 27 | pathMatch: 'full', 28 | }, 29 | { 30 | path: 'signup', 31 | component: SignupComponent, 32 | pathMatch: 'full', 33 | }, 34 | { 35 | path: 'login', 36 | component: LoginComponent, 37 | pathMatch: 'full', 38 | }, 39 | { 40 | path: 'admin', 41 | component: DashboardComponent, 42 | canActivate: [AdminGuard], 43 | children: [ 44 | { 45 | path: '', 46 | component: WelcomeComponent, 47 | }, 48 | { 49 | path: 'profile', 50 | component: ProfileComponent, 51 | }, 52 | { 53 | path: 'categories', 54 | component: ViewCategoriesComponent, 55 | }, 56 | { 57 | path: 'add-category', 58 | component: AddCategoryComponent, 59 | }, 60 | { 61 | path: 'quizzes', 62 | component: ViewQuizzesComponent, 63 | }, 64 | { 65 | path: 'add-quiz', 66 | component: AddQuizComponent, 67 | }, 68 | { 69 | path: 'quiz/:qid', 70 | component: UpdateQuizComponent, 71 | }, 72 | { 73 | path: 'view-questions/:qid/:title', 74 | component: ViewQuizQuestionsComponent, 75 | }, 76 | { 77 | path: 'add-question/:qid/:title', 78 | component: AddQuestionComponent, 79 | }, 80 | ], 81 | }, 82 | { 83 | path: 'user-dashboard', 84 | component: UserDashboardComponent, 85 | canActivate: [NormalGuard], 86 | children: [ 87 | { 88 | path: ':catId', 89 | component: LoadQuizComponent, 90 | }, 91 | { 92 | path: 'instructions/:qid', 93 | component: InstructionsComponent, 94 | }, 95 | ], 96 | }, 97 | 98 | { 99 | path: 'start/:qid', 100 | component: StartComponent, 101 | canActivate: [NormalGuard], 102 | }, 103 | ]; 104 | 105 | @NgModule({ 106 | imports: [RouterModule.forRoot(routes)], 107 | exports: [RouterModule], 108 | }) 109 | export class AppRoutingModule {} 110 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/controller/QuestionController.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.controller; 2 | 3 | import com.examenv.examserver.model.exam.Question; 4 | import com.examenv.examserver.model.exam.Quiz; 5 | import com.examenv.examserver.service.QuestionService; 6 | import com.examenv.examserver.service.QuizService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import java.util.*; 12 | 13 | @RestController 14 | @CrossOrigin("*") 15 | @RequestMapping("/question") 16 | public class QuestionController { 17 | 18 | @Autowired 19 | private QuestionService questionService; 20 | 21 | @Autowired 22 | private QuizService quizService; 23 | 24 | //add question 25 | @PostMapping("/") 26 | public ResponseEntity add(@RequestBody Question question){ 27 | return ResponseEntity.ok(this.questionService.addQuestion(question)); 28 | } 29 | 30 | //update question 31 | @PutMapping("/") 32 | public ResponseEntity update(@RequestBody Question question){ 33 | return ResponseEntity.ok(this.questionService.updateQuestion(question)); 34 | } 35 | 36 | // get all questions 37 | @GetMapping("/quiz/{qid}") 38 | public ResponseEntity getQuestionsOfQuiz(@PathVariable("qid") Long qid){ 39 | /* 40 | Quiz quiz = new Quiz(); 41 | quiz.setqId(qid); 42 | Set questionsOfQuiz = this.questionService.getQuestionsOfQuiz(quiz); 43 | return ResponseEntity.ok(questionsOfQuiz); 44 | */ 45 | Quiz quiz = this.quizService.getQuiz(qid); 46 | Set questions = quiz.getQuestions(); 47 | List list = new ArrayList(questions); 48 | if (list.size() > Integer.parseInt(quiz.getNumberOfQuestions())){ 49 | list = list.subList(0,Integer.parseInt(quiz.getNumberOfQuestions()+1)); 50 | } 51 | list.forEach((q)->{ 52 | q.setAnswer(""); 53 | }); 54 | Collections.shuffle(list); 55 | return ResponseEntity.ok(list); 56 | } 57 | 58 | 59 | @GetMapping("/quiz/all/{qid}") 60 | public ResponseEntity getQuestionsOfQuizAdmin(@PathVariable("qid") Long qid){ 61 | Quiz quiz = new Quiz(); 62 | quiz.setqId(qid); 63 | Set questionsOfQuiz = this.questionService.getQuestionsOfQuiz(quiz); 64 | return ResponseEntity.ok(questionsOfQuiz); 65 | } 66 | 67 | 68 | 69 | 70 | //get single question 71 | @GetMapping("/{questionId}") 72 | public Question get(@PathVariable("questionId") Long questionId){ 73 | return this.questionService.getQuestion(questionId); 74 | } 75 | 76 | //delete question 77 | @DeleteMapping("/{questionId}") 78 | public void delete(@PathVariable("questionId") Long questionId){ 79 | this.questionService.deleteQuestion(questionId); 80 | } 81 | 82 | 83 | //evaluate quiz 84 | @PostMapping("/eval-quiz") 85 | public ResponseEntity evalQuiz(@RequestBody List questions){ 86 | System.out.println(questions); 87 | double marksGained=0; 88 | int correctAnswers = 0; 89 | int attempted = 0; 90 | for(Question q: questions){ 91 | Question question = this.questionService.get(q.getQuestionId()); 92 | if(question.getAnswer().equals(q.getGivenAnswer().trim())){ 93 | //correct 94 | correctAnswers++; 95 | double marksSingle = Double.parseDouble(questions.get(0).getQuiz().getMaxMark()) / questions.size(); 96 | marksGained += marksSingle; 97 | } 98 | if(q.getGivenAnswer() != null){ 99 | attempted++; 100 | } 101 | } 102 | 103 | Map map = Map.of("marksGained",marksGained,"correctAnswers",correctAnswers,"attempted",attempted); 104 | return ResponseEntity.ok(map); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /examserver/src/main/java/com/examenv/examserver/model/User.java: -------------------------------------------------------------------------------- 1 | package com.examenv.examserver.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import org.springframework.security.core.GrantedAuthority; 5 | import org.springframework.security.core.userdetails.UserDetails; 6 | import javax.persistence.*; 7 | import java.util.Collection; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | @Entity 12 | @Table(name = "users") 13 | public class User implements UserDetails { 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.AUTO) 16 | private Long id; 17 | private String username; 18 | private String password; 19 | private String firstName; 20 | private String lastName; 21 | private String email; 22 | private String phone; 23 | private boolean enabled = true; 24 | private String profile; 25 | 26 | //user may have many roles 27 | @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "user") 28 | @JsonIgnore 29 | private Set userRoles = new HashSet<>(); 30 | public User() { 31 | } 32 | 33 | public User(Long id, String username, String password, String firstName, String lastName, String email, String phone, boolean enabled, String profile) { 34 | this.id = id; 35 | this.username = username; 36 | this.password = password; 37 | this.firstName = firstName; 38 | this.lastName = lastName; 39 | this.email = email; 40 | this.phone = phone; 41 | this.enabled = enabled; 42 | this.profile = profile; 43 | } 44 | 45 | public Set getUserRoles() { 46 | return userRoles; 47 | } 48 | 49 | public void setUserRoles(Set userRoles) { 50 | this.userRoles = userRoles; 51 | } 52 | 53 | public String getProfile() { 54 | return profile; 55 | } 56 | 57 | public void setProfile(String profile) { 58 | this.profile = profile; 59 | } 60 | 61 | public Long getId() { 62 | return id; 63 | } 64 | 65 | public void setId(Long id) { 66 | this.id = id; 67 | } 68 | 69 | public String getUsername() { 70 | return username; 71 | } 72 | 73 | @Override 74 | public boolean isAccountNonExpired() { 75 | return true; 76 | } 77 | 78 | @Override 79 | public boolean isAccountNonLocked() { 80 | return true; 81 | } 82 | 83 | @Override 84 | public boolean isCredentialsNonExpired() { 85 | return true; 86 | } 87 | 88 | public void setUsername(String username) { 89 | this.username = username; 90 | } 91 | 92 | @Override 93 | public Collection getAuthorities() { 94 | 95 | Set set = new HashSet<>(); 96 | 97 | this.userRoles.forEach(userRole -> { 98 | set.add(new Authority(userRole.getRole().getRoleName())); 99 | }); 100 | 101 | return set; 102 | } 103 | 104 | public String getPassword() { 105 | return password; 106 | } 107 | 108 | public void setPassword(String password) { 109 | this.password = password; 110 | } 111 | 112 | public String getFirstName() { 113 | return firstName; 114 | } 115 | 116 | public void setFirstName(String firstName) { 117 | this.firstName = firstName; 118 | } 119 | 120 | public String getLastName() { 121 | return lastName; 122 | } 123 | 124 | public void setLastName(String lastName) { 125 | this.lastName = lastName; 126 | } 127 | 128 | public String getEmail() { 129 | return email; 130 | } 131 | 132 | public void setEmail(String email) { 133 | this.email = email; 134 | } 135 | 136 | public String getPhone() { 137 | return phone; 138 | } 139 | 140 | public void setPhone(String phone) { 141 | this.phone = phone; 142 | } 143 | 144 | public boolean isEnabled() { 145 | return enabled; 146 | } 147 | 148 | public void setEnabled(boolean enabled) { 149 | this.enabled = enabled; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /examenvfront/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppRoutingModule } from './app-routing.module'; 5 | import { AppComponent } from './app.component'; 6 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 7 | import { MatButtonModule } from '@angular/material/button'; 8 | import { NavbarComponent } from './components/navbar/navbar.component'; 9 | import { FooterComponent } from './components/footer/footer.component'; 10 | import { SignupComponent } from './pages/signup/signup.component'; 11 | import { LoginComponent } from './pages/login/login.component'; 12 | import {MatInputModule} from '@angular/material/input'; 13 | import {MatFormFieldModule} from '@angular/material/form-field'; 14 | import { FormsModule } from '@angular/forms'; 15 | import {HttpClientModule} from '@angular/common/http'; 16 | import {MatSnackBarModule} from '@angular/material/snack-bar'; 17 | import { HomeComponent } from './pages/home/home.component'; 18 | import {MatCardModule} from '@angular/material/card'; 19 | import {MatToolbarModule} from '@angular/material/toolbar'; 20 | import {MatIconModule} from '@angular/material/icon'; 21 | import { authInterceptorProviders } from './services/auth.interceptor'; 22 | import { DashboardComponent } from './pages/admin/dashboard/dashboard.component'; 23 | import { UserDashboardComponent } from './pages/user/user-dashboard/user-dashboard.component'; 24 | import { ProfileComponent } from './pages/profile/profile.component'; 25 | import {MatListModule} from '@angular/material/list'; 26 | import { SidebarComponent } from './pages/admin/sidebar/sidebar.component'; 27 | import { WelcomeComponent } from './pages/admin/welcome/welcome.component'; 28 | import { ViewCategoriesComponent } from './pages/admin/view-categories/view-categories.component'; 29 | import { AddCategoryComponent } from './pages/admin/add-category/add-category.component'; 30 | import { ViewQuizzesComponent } from './pages/admin/view-quizzes/view-quizzes.component'; 31 | import { AddQuizComponent } from './pages/admin/add-quiz/add-quiz.component'; 32 | import {MatSlideToggleModule} from '@angular/material/slide-toggle'; 33 | import {MatSelectModule} from '@angular/material/select'; 34 | import { UpdateQuizComponent } from './pages/admin/update-quiz/update-quiz.component'; 35 | import { ViewQuizQuestionsComponent } from './pages/admin/view-quiz-questions/view-quiz-questions.component'; 36 | import { AddQuestionComponent } from './pages/admin/add-question/add-question.component'; 37 | import { SidebarComponent as UserSidebar } from './pages/user/sidebar/sidebar.component'; 38 | import { LoadQuizComponent } from './pages/user/load-quiz/load-quiz.component'; 39 | import { InstructionsComponent } from './pages/user/instructions/instructions.component'; 40 | import { StartComponent } from './pages/user/start/start.component'; 41 | import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; 42 | import { NgxUiLoaderModule,NgxUiLoaderHttpModule } from "ngx-ui-loader"; 43 | 44 | 45 | @NgModule({ 46 | declarations: [ 47 | AppComponent, 48 | NavbarComponent, 49 | FooterComponent, 50 | SignupComponent, 51 | LoginComponent, 52 | HomeComponent, 53 | DashboardComponent, 54 | UserDashboardComponent, 55 | ProfileComponent, 56 | SidebarComponent, 57 | WelcomeComponent, 58 | ViewCategoriesComponent, 59 | AddCategoryComponent, 60 | ViewQuizzesComponent, 61 | AddQuizComponent, 62 | UpdateQuizComponent, 63 | ViewQuizQuestionsComponent, 64 | AddQuestionComponent, 65 | UserSidebar, 66 | LoadQuizComponent, 67 | InstructionsComponent, 68 | StartComponent, 69 | ], 70 | imports: [ 71 | BrowserModule, 72 | AppRoutingModule, 73 | BrowserAnimationsModule, 74 | MatButtonModule, 75 | MatInputModule, 76 | MatFormFieldModule, 77 | FormsModule, 78 | HttpClientModule, 79 | MatSnackBarModule, 80 | MatCardModule, 81 | MatToolbarModule, 82 | MatIconModule, 83 | MatListModule, 84 | MatSlideToggleModule, 85 | MatSelectModule, 86 | MatProgressSpinnerModule, 87 | NgxUiLoaderModule, 88 | NgxUiLoaderHttpModule.forRoot({ 89 | showForeground: true, 90 | }), 91 | ], 92 | providers: [authInterceptorProviders], 93 | bootstrap: [AppComponent] 94 | }) 95 | export class AppModule { } 96 | -------------------------------------------------------------------------------- /examserver/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /examserver/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | --------------------------------------------------------------------------------