Fix report card (#1845)
* fix: report card Fix and simplify calculation of the number of assignments a user solved. Rename `UserTracker` to `UserProgress` Rename `LessonTracker` to `LessonProgress` Rename tables in database
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/branchbuild.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/branchbuild.txt
									
									
									
									
										vendored
									
									
								
							| @ -11,7 +11,7 @@ jobs: | |||||||
|         strategy: |         strategy: | ||||||
|             matrix: |             matrix: | ||||||
|                 os: [ ubuntu-latest, windows-latest, macos-latest ] |                 os: [ ubuntu-latest, windows-latest, macos-latest ] | ||||||
|                 java-version: [ 17, 21 ] |                 java-version: [ 21 ] | ||||||
|         steps: |         steps: | ||||||
|             -   uses: actions/checkout@v4 |             -   uses: actions/checkout@v4 | ||||||
|             -   name: Set up JDK ${{ matrix.java-version }} |             -   name: Set up JDK ${{ matrix.java-version }} | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -14,8 +14,10 @@ jobs: | |||||||
|     build: |     build: | ||||||
|         runs-on: ${{ matrix.os }} |         runs-on: ${{ matrix.os }} | ||||||
|         strategy: |         strategy: | ||||||
|  |             fail-fast: true | ||||||
|             matrix: |             matrix: | ||||||
|                 os: [ ubuntu-latest, windows-latest, macos-latest ] |                 os: [ windows-latest, ubuntu-latest, macos-13 ] | ||||||
|  |             max-parallel: 1 | ||||||
|         steps: |         steps: | ||||||
|             -   uses: actions/checkout@v4.1.6 |             -   uses: actions/checkout@v4.1.6 | ||||||
|             -   name: Set up JDK 21 |             -   name: Set up JDK 21 | ||||||
| @ -31,16 +33,4 @@ jobs: | |||||||
|                     key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} |                     key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} | ||||||
|                     restore-keys: ${{ runner.os }}-m2- |                     restore-keys: ${{ runner.os }}-m2- | ||||||
|             -   name: Build with Maven |             -   name: Build with Maven | ||||||
|                 run: | |                 run: mvn --no-transfer-progress verify | ||||||
|                     if [ "$RUNNER_OS" == "macOS" ]; then |  | ||||||
|                         # Make "localhost" DNS entry available; see https://github.com/actions/runner-images/issues/6383 |  | ||||||
|                         # sudo networksetup -setdnsservers Ethernet 9.9.9.9 |  | ||||||
|                         echo -e "$(ipconfig getifaddr en0) $(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts |  | ||||||
|                         echo `sudo lsof -PiTCP -sTCP:LISTEN` |  | ||||||
|                         cat /etc/hosts |  | ||||||
|                         mvn --no-transfer-progress verify -DskipTests -DwaittimeForServerStart=150 |  | ||||||
|                         # skip tests on macos, takes too long with the current runners |  | ||||||
|                     else |  | ||||||
|                         mvn --no-transfer-progress verify -DwaittimeForServerStart=30 |  | ||||||
|                     fi |  | ||||||
|                 shell: bash |  | ||||||
|  | |||||||
							
								
								
									
										0
									
								
								.github/workflows/semgrep.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								.github/workflows/semgrep.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
									
										4
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								pom.xml
									
									
									
									
									
								
							| @ -669,10 +669,6 @@ | |||||||
|       <plugin> |       <plugin> | ||||||
|         <groupId>org.apache.maven.plugins</groupId> |         <groupId>org.apache.maven.plugins</groupId> | ||||||
|         <artifactId>maven-compiler-plugin</artifactId> |         <artifactId>maven-compiler-plugin</artifactId> | ||||||
|         <configuration> |  | ||||||
|           <source>17</source> |  | ||||||
|           <target>17</target> |  | ||||||
|         </configuration> |  | ||||||
|       </plugin> |       </plugin> | ||||||
|     </plugins> |     </plugins> | ||||||
|   </build> |   </build> | ||||||
|  | |||||||
| @ -23,8 +23,8 @@ | |||||||
| package org.owasp.webgoat.container.assignments; | package org.owasp.webgoat.container.assignments; | ||||||
|  |  | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.core.MethodParameter; | import org.springframework.core.MethodParameter; | ||||||
| import org.springframework.http.MediaType; | import org.springframework.http.MediaType; | ||||||
| import org.springframework.http.converter.HttpMessageConverter; | import org.springframework.http.converter.HttpMessageConverter; | ||||||
| @ -36,11 +36,11 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; | |||||||
| @RestControllerAdvice | @RestControllerAdvice | ||||||
| public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> { | public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> { | ||||||
|  |  | ||||||
|   private UserTrackerRepository userTrackerRepository; |   private UserProgressRepository userTrackerRepository; | ||||||
|   private WebSession webSession; |   private WebSession webSession; | ||||||
|  |  | ||||||
|   public LessonTrackerInterceptor( |   public LessonTrackerInterceptor( | ||||||
|       UserTrackerRepository userTrackerRepository, WebSession webSession) { |       UserProgressRepository userTrackerRepository, WebSession webSession) { | ||||||
|     this.userTrackerRepository = userTrackerRepository; |     this.userTrackerRepository = userTrackerRepository; | ||||||
|     this.webSession = webSession; |     this.webSession = webSession; | ||||||
|   } |   } | ||||||
| @ -66,9 +66,9 @@ public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected AttackResult trackProgress(AttackResult attackResult) { |   protected AttackResult trackProgress(AttackResult attackResult) { | ||||||
|     UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); |     UserProgress userTracker = userTrackerRepository.findByUser(webSession.getUserName()); | ||||||
|     if (userTracker == null) { |     if (userTracker == null) { | ||||||
|       userTracker = new UserTracker(webSession.getUserName()); |       userTracker = new UserProgress(webSession.getUserName()); | ||||||
|     } |     } | ||||||
|     if (attackResult.assignmentSolved()) { |     if (attackResult.assignmentSolved()) { | ||||||
|       userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment()); |       userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment()); | ||||||
|  | |||||||
| @ -54,7 +54,7 @@ public class Assignment { | |||||||
|  |  | ||||||
|   @Transient private List<String> hints; |   @Transient private List<String> hints; | ||||||
|  |  | ||||||
|   private Assignment() { |   protected Assignment() { | ||||||
|     // Hibernate |     // Hibernate | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | |||||||
| @ -0,0 +1,3 @@ | |||||||
|  | package org.owasp.webgoat.container.report; | ||||||
|  |  | ||||||
|  | record LessonStatistics(String name, boolean solved, int numberOfAttempts) {} | ||||||
| @ -0,0 +1,93 @@ | |||||||
|  | /** | ||||||
|  |  * ************************************************************************************************* | ||||||
|  |  * | ||||||
|  |  * <p> | ||||||
|  |  * | ||||||
|  |  * <p>This file is part of WebGoat, an Open Web Application Security Project utility. For details, | ||||||
|  |  * please see http://www.owasp.org/ | ||||||
|  |  * | ||||||
|  |  * <p>Copyright (c) 2002 - 2014 Bruce Mayhew | ||||||
|  |  * | ||||||
|  |  * <p>This program is free software; you can redistribute it and/or modify it under the terms of the | ||||||
|  |  * GNU General Public License as published by the Free Software Foundation; either version 2 of the | ||||||
|  |  * License, or (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | ||||||
|  |  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * <p>You should have received a copy of the GNU General Public License along with this program; if | ||||||
|  |  * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||||||
|  |  * 02111-1307, USA. | ||||||
|  |  * | ||||||
|  |  * <p>Getting Source ============== | ||||||
|  |  * | ||||||
|  |  * <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository | ||||||
|  |  * for free software projects. | ||||||
|  |  */ | ||||||
|  | package org.owasp.webgoat.container.report; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  | import org.owasp.webgoat.container.i18n.PluginMessages; | ||||||
|  | import org.owasp.webgoat.container.session.Course; | ||||||
|  | import org.owasp.webgoat.container.session.WebSession; | ||||||
|  | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
|  | import org.springframework.web.bind.annotation.GetMapping; | ||||||
|  | import org.springframework.web.bind.annotation.ResponseBody; | ||||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||||
|  |  | ||||||
|  | @RestController | ||||||
|  | public class ReportCardController { | ||||||
|  |  | ||||||
|  |   private final WebSession webSession; | ||||||
|  |   private final UserProgressRepository userProgressRepository; | ||||||
|  |   private final Course course; | ||||||
|  |   private final PluginMessages pluginMessages; | ||||||
|  |  | ||||||
|  |   public ReportCardController( | ||||||
|  |       WebSession webSession, | ||||||
|  |       UserProgressRepository userProgressRepository, | ||||||
|  |       Course course, | ||||||
|  |       PluginMessages pluginMessages) { | ||||||
|  |     this.webSession = webSession; | ||||||
|  |     this.userProgressRepository = userProgressRepository; | ||||||
|  |     this.course = course; | ||||||
|  |     this.pluginMessages = pluginMessages; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Endpoint which generates the report card for the current use to show the stats on the solved | ||||||
|  |    * lessons | ||||||
|  |    */ | ||||||
|  |   @GetMapping(path = "/service/reportcard.mvc", produces = "application/json") | ||||||
|  |   @ResponseBody | ||||||
|  |   public ReportCard reportCard() { | ||||||
|  |     var userProgress = userProgressRepository.findByUser(webSession.getUserName()); | ||||||
|  |     var lessonStatistics = | ||||||
|  |         course.getLessons().stream() | ||||||
|  |             .map( | ||||||
|  |                 lesson -> { | ||||||
|  |                   var lessonTracker = userProgress.getLessonProgress(lesson); | ||||||
|  |                   return new LessonStatistics( | ||||||
|  |                       pluginMessages.getMessage(lesson.getTitle()), | ||||||
|  |                       lessonTracker.isLessonSolved(), | ||||||
|  |                       lessonTracker.getNumberOfAttempts()); | ||||||
|  |                 }) | ||||||
|  |             .toList(); | ||||||
|  |     return new ReportCard( | ||||||
|  |         course.getTotalOfLessons(), | ||||||
|  |         course.getTotalOfAssignments(), | ||||||
|  |         userProgress.numberOfAssignmentsSolved(), | ||||||
|  |         userProgress.numberOfLessonsSolved(), | ||||||
|  |         lessonStatistics); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private record ReportCard( | ||||||
|  |       int totalNumberOfLessons, | ||||||
|  |       int totalNumberOfAssignments, | ||||||
|  |       long numberOfAssignmentsSolved, | ||||||
|  |       long numberOfLessonsSolved, | ||||||
|  |       List<LessonStatistics> lessonStatistics) {} | ||||||
|  |  | ||||||
|  |   private record LessonStatistics(String name, boolean solved, int numberOfAttempts) {} | ||||||
|  | } | ||||||
| @ -39,9 +39,9 @@ import org.owasp.webgoat.container.lessons.LessonMenuItem; | |||||||
| import org.owasp.webgoat.container.lessons.LessonMenuItemType; | import org.owasp.webgoat.container.lessons.LessonMenuItemType; | ||||||
| import org.owasp.webgoat.container.session.Course; | import org.owasp.webgoat.container.session.Course; | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.LessonTracker; | import org.owasp.webgoat.container.users.LessonProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.stereotype.Controller; | import org.springframework.stereotype.Controller; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| @ -60,7 +60,7 @@ public class LessonMenuService { | |||||||
|   public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc"; |   public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc"; | ||||||
|   private final Course course; |   private final Course course; | ||||||
|   private final WebSession webSession; |   private final WebSession webSession; | ||||||
|   private UserTrackerRepository userTrackerRepository; |   private UserProgressRepository userTrackerRepository; | ||||||
|  |  | ||||||
|   @Value("#{'${exclude.categories}'.split(',')}") |   @Value("#{'${exclude.categories}'.split(',')}") | ||||||
|   private List<String> excludeCategories; |   private List<String> excludeCategories; | ||||||
| @ -77,7 +77,7 @@ public class LessonMenuService { | |||||||
|   public @ResponseBody List<LessonMenuItem> showLeftNav() { |   public @ResponseBody List<LessonMenuItem> showLeftNav() { | ||||||
|     List<LessonMenuItem> menu = new ArrayList<>(); |     List<LessonMenuItem> menu = new ArrayList<>(); | ||||||
|     List<Category> categories = course.getCategories(); |     List<Category> categories = course.getCategories(); | ||||||
|     UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); |     UserProgress userTracker = userTrackerRepository.findByUser(webSession.getUserName()); | ||||||
|  |  | ||||||
|     for (Category category : categories) { |     for (Category category : categories) { | ||||||
|       if (excludeCategories.contains(category.name())) { |       if (excludeCategories.contains(category.name())) { | ||||||
| @ -97,7 +97,7 @@ public class LessonMenuService { | |||||||
|         lessonItem.setName(lesson.getTitle()); |         lessonItem.setName(lesson.getTitle()); | ||||||
|         lessonItem.setLink(lesson.getLink()); |         lessonItem.setLink(lesson.getLink()); | ||||||
|         lessonItem.setType(LessonMenuItemType.LESSON); |         lessonItem.setType(LessonMenuItemType.LESSON); | ||||||
|         LessonTracker lessonTracker = userTracker.getLessonTracker(lesson); |         LessonProgress lessonTracker = userTracker.getLessonProgress(lesson); | ||||||
|         boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson); |         boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson); | ||||||
|         lessonItem.setComplete(lessonSolved); |         lessonItem.setComplete(lessonSolved); | ||||||
|         categoryItem.addChild(lessonItem); |         categoryItem.addChild(lessonItem); | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ import lombok.Getter; | |||||||
| import lombok.RequiredArgsConstructor; | import lombok.RequiredArgsConstructor; | ||||||
| import org.owasp.webgoat.container.lessons.Assignment; | import org.owasp.webgoat.container.lessons.Assignment; | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.stereotype.Controller; | import org.springframework.stereotype.Controller; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.ResponseBody; | import org.springframework.web.bind.annotation.ResponseBody; | ||||||
| @ -20,7 +20,7 @@ import org.springframework.web.bind.annotation.ResponseBody; | |||||||
| @RequiredArgsConstructor | @RequiredArgsConstructor | ||||||
| public class LessonProgressService { | public class LessonProgressService { | ||||||
|  |  | ||||||
|   private final UserTrackerRepository userTrackerRepository; |   private final UserProgressRepository userTrackerRepository; | ||||||
|   private final WebSession webSession; |   private final WebSession webSession; | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @ -36,7 +36,7 @@ public class LessonProgressService { | |||||||
|     var currentLesson = webSession.getCurrentLesson(); |     var currentLesson = webSession.getCurrentLesson(); | ||||||
|  |  | ||||||
|     if (currentLesson != null) { |     if (currentLesson != null) { | ||||||
|       var lessonTracker = userTracker.getLessonTracker(currentLesson); |       var lessonTracker = userTracker.getLessonProgress(currentLesson); | ||||||
|       return lessonTracker.getLessonOverview().entrySet().stream() |       return lessonTracker.getLessonOverview().entrySet().stream() | ||||||
|           .map(entry -> new LessonOverview(entry.getKey(), entry.getValue())) |           .map(entry -> new LessonOverview(entry.getKey(), entry.getValue())) | ||||||
|           .toList(); |           .toList(); | ||||||
|  | |||||||
| @ -1,105 +0,0 @@ | |||||||
| /** |  | ||||||
|  * ************************************************************************************************* |  | ||||||
|  * |  | ||||||
|  * <p> |  | ||||||
|  * |  | ||||||
|  * <p>This file is part of WebGoat, an Open Web Application Security Project utility. For details, |  | ||||||
|  * please see http://www.owasp.org/ |  | ||||||
|  * |  | ||||||
|  * <p>Copyright (c) 2002 - 2014 Bruce Mayhew |  | ||||||
|  * |  | ||||||
|  * <p>This program is free software; you can redistribute it and/or modify it under the terms of the |  | ||||||
|  * GNU General Public License as published by the Free Software Foundation; either version 2 of the |  | ||||||
|  * License, or (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |  | ||||||
|  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  * <p>You should have received a copy of the GNU General Public License along with this program; if |  | ||||||
|  * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |  | ||||||
|  * 02111-1307, USA. |  | ||||||
|  * |  | ||||||
|  * <p>Getting Source ============== |  | ||||||
|  * |  | ||||||
|  * <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository |  | ||||||
|  * for free software projects. |  | ||||||
|  */ |  | ||||||
| package org.owasp.webgoat.container.service; |  | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.List; |  | ||||||
| import lombok.AllArgsConstructor; |  | ||||||
| import lombok.Getter; |  | ||||||
| import lombok.Setter; |  | ||||||
| import org.owasp.webgoat.container.i18n.PluginMessages; |  | ||||||
| import org.owasp.webgoat.container.lessons.Lesson; |  | ||||||
| import org.owasp.webgoat.container.session.Course; |  | ||||||
| import org.owasp.webgoat.container.session.WebSession; |  | ||||||
| import org.owasp.webgoat.container.users.LessonTracker; |  | ||||||
| import org.owasp.webgoat.container.users.UserTracker; |  | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; |  | ||||||
| import org.springframework.stereotype.Controller; |  | ||||||
| import org.springframework.web.bind.annotation.GetMapping; |  | ||||||
| import org.springframework.web.bind.annotation.ResponseBody; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * ReportCardService |  | ||||||
|  * |  | ||||||
|  * @author nbaars |  | ||||||
|  * @version $Id: $Id |  | ||||||
|  */ |  | ||||||
| @Controller |  | ||||||
| @AllArgsConstructor |  | ||||||
| public class ReportCardService { |  | ||||||
|  |  | ||||||
|   private final WebSession webSession; |  | ||||||
|   private final UserTrackerRepository userTrackerRepository; |  | ||||||
|   private final Course course; |  | ||||||
|   private final PluginMessages pluginMessages; |  | ||||||
|  |  | ||||||
|   /** |  | ||||||
|    * Endpoint which generates the report card for the current use to show the stats on the solved |  | ||||||
|    * lessons |  | ||||||
|    */ |  | ||||||
|   @GetMapping(path = "/service/reportcard.mvc", produces = "application/json") |  | ||||||
|   @ResponseBody |  | ||||||
|   public ReportCard reportCard() { |  | ||||||
|     final ReportCard reportCard = new ReportCard(); |  | ||||||
|     reportCard.setTotalNumberOfLessons(course.getTotalOfLessons()); |  | ||||||
|     reportCard.setTotalNumberOfAssignments(course.getTotalOfAssignments()); |  | ||||||
|  |  | ||||||
|     UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); |  | ||||||
|     reportCard.setNumberOfAssignmentsSolved(userTracker.numberOfAssignmentsSolved()); |  | ||||||
|     reportCard.setNumberOfLessonsSolved(userTracker.numberOfLessonsSolved()); |  | ||||||
|     for (Lesson lesson : course.getLessons()) { |  | ||||||
|       LessonTracker lessonTracker = userTracker.getLessonTracker(lesson); |  | ||||||
|       final LessonStatistics lessonStatistics = new LessonStatistics(); |  | ||||||
|       lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle())); |  | ||||||
|       lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts()); |  | ||||||
|       lessonStatistics.setSolved(lessonTracker.isLessonSolved()); |  | ||||||
|       reportCard.lessonStatistics.add(lessonStatistics); |  | ||||||
|     } |  | ||||||
|     return reportCard; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @Getter |  | ||||||
|   @Setter |  | ||||||
|   private final class ReportCard { |  | ||||||
|  |  | ||||||
|     private int totalNumberOfLessons; |  | ||||||
|     private int totalNumberOfAssignments; |  | ||||||
|     private int solvedLessons; |  | ||||||
|     private int numberOfAssignmentsSolved; |  | ||||||
|     private int numberOfLessonsSolved; |  | ||||||
|     private List<LessonStatistics> lessonStatistics = new ArrayList<>(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @Setter |  | ||||||
|   @Getter |  | ||||||
|   private final class LessonStatistics { |  | ||||||
|     private String name; |  | ||||||
|     private boolean solved; |  | ||||||
|     private int numberOfAttempts; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -32,8 +32,8 @@ import org.flywaydb.core.Flyway; | |||||||
| import org.owasp.webgoat.container.lessons.Initializeable; | import org.owasp.webgoat.container.lessons.Initializeable; | ||||||
| import org.owasp.webgoat.container.lessons.Lesson; | import org.owasp.webgoat.container.lessons.Lesson; | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.http.HttpStatus; | import org.springframework.http.HttpStatus; | ||||||
| import org.springframework.stereotype.Controller; | import org.springframework.stereotype.Controller; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| @ -45,7 +45,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; | |||||||
| public class RestartLessonService { | public class RestartLessonService { | ||||||
|  |  | ||||||
|   private final WebSession webSession; |   private final WebSession webSession; | ||||||
|   private final UserTrackerRepository userTrackerRepository; |   private final UserProgressRepository userTrackerRepository; | ||||||
|   private final Function<String, Flyway> flywayLessons; |   private final Function<String, Flyway> flywayLessons; | ||||||
|   private final List<Initializeable> lessonsToInitialize; |   private final List<Initializeable> lessonsToInitialize; | ||||||
|  |  | ||||||
| @ -55,7 +55,7 @@ public class RestartLessonService { | |||||||
|     Lesson al = webSession.getCurrentLesson(); |     Lesson al = webSession.getCurrentLesson(); | ||||||
|     log.debug("Restarting lesson: " + al); |     log.debug("Restarting lesson: " + al); | ||||||
|  |  | ||||||
|     UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); |     UserProgress userTracker = userTrackerRepository.findByUser(webSession.getUserName()); | ||||||
|     userTracker.reset(al); |     userTracker.reset(al); | ||||||
|     userTrackerRepository.save(userTracker); |     userTrackerRepository.save(userTracker); | ||||||
|  |  | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ import org.owasp.webgoat.container.lessons.Lesson; | |||||||
|  */ |  */ | ||||||
| @Entity | @Entity | ||||||
| @EqualsAndHashCode | @EqualsAndHashCode | ||||||
| public class LessonTracker { | public class LessonProgress { | ||||||
| 
 | 
 | ||||||
|   @Id |   @Id | ||||||
|   @GeneratedValue(strategy = GenerationType.IDENTITY) |   @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||
| @ -69,11 +69,11 @@ public class LessonTracker { | |||||||
|   @Getter private int numberOfAttempts = 0; |   @Getter private int numberOfAttempts = 0; | ||||||
|   @Version private Integer version; |   @Version private Integer version; | ||||||
| 
 | 
 | ||||||
|   private LessonTracker() { |   protected LessonProgress() { | ||||||
|     // JPA |     // JPA | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public LessonTracker(Lesson lesson) { |   public LessonProgress(Lesson lesson) { | ||||||
|     lessonName = lesson.getId(); |     lessonName = lesson.getId(); | ||||||
|     allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments()); |     allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments()); | ||||||
|   } |   } | ||||||
| @ -119,4 +119,8 @@ public class LessonTracker { | |||||||
|     overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true))); |     overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true))); | ||||||
|     return overview; |     return overview; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   long numberOfSolvedAssignments() { | ||||||
|  |     return solvedAssignments.size(); | ||||||
|  |   } | ||||||
| } | } | ||||||
| @ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController; | |||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| public class Scoreboard { | public class Scoreboard { | ||||||
|  |  | ||||||
|   private final UserTrackerRepository userTrackerRepository; |   private final UserProgressRepository userTrackerRepository; | ||||||
|   private final UserRepository userRepository; |   private final UserRepository userRepository; | ||||||
|   private final Course course; |   private final Course course; | ||||||
|   private final PluginMessages pluginMessages; |   private final PluginMessages pluginMessages; | ||||||
| @ -46,7 +46,7 @@ public class Scoreboard { | |||||||
|         .collect(Collectors.toList()); |         .collect(Collectors.toList()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   private List<String> challengesSolved(UserTracker userTracker) { |   private List<String> challengesSolved(UserProgress userTracker) { | ||||||
|     List<String> challenges = |     List<String> challenges = | ||||||
|         List.of( |         List.of( | ||||||
|             "Challenge1", |             "Challenge1", | ||||||
| @ -59,10 +59,10 @@ public class Scoreboard { | |||||||
|             "Challenge8", |             "Challenge8", | ||||||
|             "Challenge9"); |             "Challenge9"); | ||||||
|     return challenges.stream() |     return challenges.stream() | ||||||
|         .map(userTracker::getLessonTracker) |         .map(userTracker::getLessonProgress) | ||||||
|         .flatMap(Optional::stream) |         .flatMap(Optional::stream) | ||||||
|         .filter(LessonTracker::isLessonSolved) |         .filter(LessonProgress::isLessonSolved) | ||||||
|         .map(LessonTracker::getLessonName) |         .map(LessonProgress::getLessonName) | ||||||
|         .map(this::toLessonTitle) |         .map(this::toLessonTitle) | ||||||
|         .toList(); |         .toList(); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -9,13 +9,10 @@ import jakarta.persistence.GenerationType; | |||||||
| import jakarta.persistence.Id; | import jakarta.persistence.Id; | ||||||
| import jakarta.persistence.OneToMany; | import jakarta.persistence.OneToMany; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.Map; |  | ||||||
| import java.util.Optional; | import java.util.Optional; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.stream.Collectors; |  | ||||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.owasp.webgoat.container.lessons.Assignment; |  | ||||||
| import org.owasp.webgoat.container.lessons.Lesson; | import org.owasp.webgoat.container.lessons.Lesson; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -52,7 +49,7 @@ import org.owasp.webgoat.container.lessons.Lesson; | |||||||
| @Slf4j | @Slf4j | ||||||
| @Entity | @Entity | ||||||
| @EqualsAndHashCode | @EqualsAndHashCode | ||||||
| public class UserTracker { | public class UserProgress { | ||||||
| 
 | 
 | ||||||
|   @Id |   @Id | ||||||
|   @GeneratedValue(strategy = GenerationType.IDENTITY) |   @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||
| @ -62,11 +59,11 @@ public class UserTracker { | |||||||
|   private String user; |   private String user; | ||||||
| 
 | 
 | ||||||
|   @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) |   @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) | ||||||
|   private Set<LessonTracker> lessonTrackers = new HashSet<>(); |   private Set<LessonProgress> lessonProgress = new HashSet<>(); | ||||||
| 
 | 
 | ||||||
|   private UserTracker() {} |   protected UserProgress() {} | ||||||
| 
 | 
 | ||||||
|   public UserTracker(final String user) { |   public UserProgress(final String user) { | ||||||
|     this.user = user; |     this.user = user; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -76,15 +73,15 @@ public class UserTracker { | |||||||
|    * @param lesson the lesson |    * @param lesson the lesson | ||||||
|    * @return a lesson tracker created if not already present |    * @return a lesson tracker created if not already present | ||||||
|    */ |    */ | ||||||
|   public LessonTracker getLessonTracker(Lesson lesson) { |   public LessonProgress getLessonProgress(Lesson lesson) { | ||||||
|     Optional<LessonTracker> lessonTracker = |     Optional<LessonProgress> progress = | ||||||
|         lessonTrackers.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst(); |         lessonProgress.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst(); | ||||||
|     if (!lessonTracker.isPresent()) { |     if (!progress.isPresent()) { | ||||||
|       LessonTracker newLessonTracker = new LessonTracker(lesson); |       LessonProgress newLessonTracker = new LessonProgress(lesson); | ||||||
|       lessonTrackers.add(newLessonTracker); |       lessonProgress.add(newLessonTracker); | ||||||
|       return newLessonTracker; |       return newLessonTracker; | ||||||
|     } else { |     } else { | ||||||
|       return lessonTracker.get(); |       return progress.get(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -94,43 +91,34 @@ public class UserTracker { | |||||||
|    * @param id the id of the lesson |    * @param id the id of the lesson | ||||||
|    * @return optional due to the fact we can only create a lesson tracker based on a lesson |    * @return optional due to the fact we can only create a lesson tracker based on a lesson | ||||||
|    */ |    */ | ||||||
|   public Optional<LessonTracker> getLessonTracker(String id) { |   public Optional<LessonProgress> getLessonProgress(String id) { | ||||||
|     return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst(); |     return lessonProgress.stream().filter(l -> l.getLessonName().equals(id)).findFirst(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public void assignmentSolved(Lesson lesson, String assignmentName) { |   public void assignmentSolved(Lesson lesson, String assignmentName) { | ||||||
|     LessonTracker lessonTracker = getLessonTracker(lesson); |     LessonProgress progress = getLessonProgress(lesson); | ||||||
|     lessonTracker.incrementAttempts(); |     progress.incrementAttempts(); | ||||||
|     lessonTracker.assignmentSolved(assignmentName); |     progress.assignmentSolved(assignmentName); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public void assignmentFailed(Lesson lesson) { |   public void assignmentFailed(Lesson lesson) { | ||||||
|     LessonTracker lessonTracker = getLessonTracker(lesson); |     LessonProgress progress = getLessonProgress(lesson); | ||||||
|     lessonTracker.incrementAttempts(); |     progress.incrementAttempts(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public void reset(Lesson al) { |   public void reset(Lesson al) { | ||||||
|     LessonTracker lessonTracker = getLessonTracker(al); |     LessonProgress progress = getLessonProgress(al); | ||||||
|     lessonTracker.reset(); |     progress.reset(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public int numberOfLessonsSolved() { |   public long numberOfLessonsSolved() { | ||||||
|     int numberOfLessonsSolved = 0; |     return lessonProgress.stream().filter(LessonProgress::isLessonSolved).count(); | ||||||
|     for (LessonTracker lessonTracker : lessonTrackers) { |  | ||||||
|       if (lessonTracker.isLessonSolved()) { |  | ||||||
|         numberOfLessonsSolved = numberOfLessonsSolved + 1; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return numberOfLessonsSolved; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public int numberOfAssignmentsSolved() { |   public long numberOfAssignmentsSolved() { | ||||||
|     int numberOfAssignmentsSolved = 0; |     return lessonProgress.stream() | ||||||
|     for (LessonTracker lessonTracker : lessonTrackers) { |         .map(LessonProgress::numberOfSolvedAssignments) | ||||||
|       Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview(); |         .mapToLong(Long::valueOf) | ||||||
|       numberOfAssignmentsSolved = |         .sum(); | ||||||
|           lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue(); |  | ||||||
|     } |  | ||||||
|     return numberOfAssignmentsSolved; |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -6,7 +6,7 @@ import org.springframework.data.jpa.repository.JpaRepository; | |||||||
|  * @author nbaars |  * @author nbaars | ||||||
|  * @since 4/30/17. |  * @since 4/30/17. | ||||||
|  */ |  */ | ||||||
| public interface UserTrackerRepository extends JpaRepository<UserTracker, String> { | public interface UserProgressRepository extends JpaRepository<UserProgress, String> { | ||||||
| 
 | 
 | ||||||
|   UserTracker findByUser(String user); |   UserProgress findByUser(String user); | ||||||
| } | } | ||||||
| @ -19,7 +19,7 @@ import org.springframework.stereotype.Service; | |||||||
| public class UserService implements UserDetailsService { | public class UserService implements UserDetailsService { | ||||||
|  |  | ||||||
|   private final UserRepository userRepository; |   private final UserRepository userRepository; | ||||||
|   private final UserTrackerRepository userTrackerRepository; |   private final UserProgressRepository userTrackerRepository; | ||||||
|   private final JdbcTemplate jdbcTemplate; |   private final JdbcTemplate jdbcTemplate; | ||||||
|   private final Function<String, Flyway> flywayLessons; |   private final Function<String, Flyway> flywayLessons; | ||||||
|   private final List<Initializeable> lessonInitializables; |   private final List<Initializeable> lessonInitializables; | ||||||
| @ -43,7 +43,7 @@ public class UserService implements UserDetailsService { | |||||||
|  |  | ||||||
|     if (!userAlreadyExists) { |     if (!userAlreadyExists) { | ||||||
|       userTrackerRepository.save( |       userTrackerRepository.save( | ||||||
|           new UserTracker(username)); // if user previously existed it will not get another tracker |           new UserProgress(username)); // if user previously existed it will not get another tracker | ||||||
|       createLessonsForUser(webGoatUser); |       createLessonsForUser(webGoatUser); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -26,8 +26,8 @@ import jakarta.servlet.http.HttpServletRequest; | |||||||
| import org.owasp.webgoat.container.assignments.AssignmentEndpoint; | import org.owasp.webgoat.container.assignments.AssignmentEndpoint; | ||||||
| import org.owasp.webgoat.container.assignments.AssignmentHints; | import org.owasp.webgoat.container.assignments.AssignmentHints; | ||||||
| import org.owasp.webgoat.container.assignments.AttackResult; | import org.owasp.webgoat.container.assignments.AttackResult; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.web.bind.annotation.PostMapping; | import org.springframework.web.bind.annotation.PostMapping; | ||||||
| import org.springframework.web.bind.annotation.ResponseBody; | import org.springframework.web.bind.annotation.ResponseBody; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| @ -40,9 +40,9 @@ import org.springframework.web.bind.annotation.RestController; | |||||||
| @AssignmentHints({"csrf-login-hint1", "csrf-login-hint2", "csrf-login-hint3"}) | @AssignmentHints({"csrf-login-hint1", "csrf-login-hint2", "csrf-login-hint3"}) | ||||||
| public class CSRFLogin extends AssignmentEndpoint { | public class CSRFLogin extends AssignmentEndpoint { | ||||||
|  |  | ||||||
|   private final UserTrackerRepository userTrackerRepository; |   private final UserProgressRepository userTrackerRepository; | ||||||
|  |  | ||||||
|   public CSRFLogin(UserTrackerRepository userTrackerRepository) { |   public CSRFLogin(UserProgressRepository userTrackerRepository) { | ||||||
|     this.userTrackerRepository = userTrackerRepository; |     this.userTrackerRepository = userTrackerRepository; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @ -60,7 +60,7 @@ public class CSRFLogin extends AssignmentEndpoint { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   private void markAssignmentSolvedWithRealUser(String username) { |   private void markAssignmentSolvedWithRealUser(String username) { | ||||||
|     UserTracker userTracker = userTrackerRepository.findByUser(username); |     UserProgress userTracker = userTrackerRepository.findByUser(username); | ||||||
|     userTracker.assignmentSolved( |     userTracker.assignmentSolved( | ||||||
|         getWebSession().getCurrentLesson(), this.getClass().getSimpleName()); |         getWebSession().getCurrentLesson(), this.getClass().getSimpleName()); | ||||||
|     userTrackerRepository.save(userTracker); |     userTrackerRepository.save(userTracker); | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								src/main/resources/db/container/V4__rename_to_progress.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/main/resources/db/container/V4__rename_to_progress.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | ALTER TABLE container.lesson_tracker | ||||||
|  |     RENAME TO container.lesson_progress; | ||||||
|  |  | ||||||
|  | ALTER TABLE container.lesson_tracker_all_assignments | ||||||
|  |     ALTER COLUMN lesson_tracker_id RENAME TO lesson_progress_id; | ||||||
|  | ALTER TABLE container.lesson_tracker_all_assignments | ||||||
|  |     RENAME TO container.lesson_progress_all_assignments; | ||||||
|  |  | ||||||
|  | ALTER TABLE container.lesson_tracker_solved_assignments | ||||||
|  |     ALTER COLUMN lesson_tracker_id RENAME TO lesson_progress_id; | ||||||
|  | ALTER TABLE container.lesson_tracker_solved_assignments | ||||||
|  |     RENAME TO container.lesson_progress_solved_assignments; | ||||||
|  |  | ||||||
|  | ALTER TABLE container.user_tracker | ||||||
|  |     RENAME TO container.user_progress; | ||||||
|  |  | ||||||
|  | ALTER TABLE container.user_tracker_lesson_trackers | ||||||
|  |     ALTER COLUMN user_tracker_id RENAME TO user_progress_id; | ||||||
|  | ALTER TABLE container.user_tracker_lesson_trackers | ||||||
|  |     ALTER COLUMN lesson_trackers_id RENAME TO lesson_progress_id; | ||||||
|  | ALTER TABLE container.user_tracker_lesson_trackers | ||||||
|  |     RENAME TO container.user_progress_lesson_progress; | ||||||
| @ -8,8 +8,7 @@ define(['jquery', | |||||||
|     'goatApp/support/GoatUtils', |     'goatApp/support/GoatUtils', | ||||||
|     'goatApp/view/UserAndInfoView', |     'goatApp/view/UserAndInfoView', | ||||||
|     'goatApp/view/MenuButtonView', |     'goatApp/view/MenuButtonView', | ||||||
|     'goatApp/model/LessonInfoModel', |     'goatApp/model/LessonInfoModel' | ||||||
|     'goatApp/view/TitleView' |  | ||||||
|     ], |     ], | ||||||
|     function($, |     function($, | ||||||
|         _, |         _, | ||||||
| @ -21,8 +20,7 @@ define(['jquery', | |||||||
|         GoatUtils, |         GoatUtils, | ||||||
|         UserAndInfoView, |         UserAndInfoView, | ||||||
|         MenuButtonView, |         MenuButtonView, | ||||||
|         LessonInfoModel, |         LessonInfoModel | ||||||
|         TitleView |  | ||||||
|     ) { |     ) { | ||||||
|         'use strict' |         'use strict' | ||||||
|  |  | ||||||
|  | |||||||
| @ -32,8 +32,8 @@ import org.owasp.webgoat.container.i18n.Messages; | |||||||
| import org.owasp.webgoat.container.i18n.PluginMessages; | import org.owasp.webgoat.container.i18n.PluginMessages; | ||||||
| import org.owasp.webgoat.container.session.UserSessionData; | import org.owasp.webgoat.container.session.UserSessionData; | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.context.support.ClassPathXmlApplicationContext; | import org.springframework.context.support.ClassPathXmlApplicationContext; | ||||||
| import org.springframework.test.util.ReflectionTestUtils; | import org.springframework.test.util.ReflectionTestUtils; | ||||||
| import org.springframework.web.servlet.i18n.FixedLocaleResolver; | import org.springframework.web.servlet.i18n.FixedLocaleResolver; | ||||||
| @ -41,8 +41,8 @@ import org.springframework.web.servlet.i18n.FixedLocaleResolver; | |||||||
| // Do not remove is the base class for all assignments tests | // Do not remove is the base class for all assignments tests | ||||||
| public class AssignmentEndpointTest { | public class AssignmentEndpointTest { | ||||||
|  |  | ||||||
|   @Mock protected UserTracker userTracker; |   @Mock protected UserProgress userTracker; | ||||||
|   @Mock protected UserTrackerRepository userTrackerRepository; |   @Mock protected UserProgressRepository userTrackerRepository; | ||||||
|   @Mock protected WebSession webSession; |   @Mock protected WebSession webSession; | ||||||
|   @Mock protected UserSessionData userSessionData; |   @Mock protected UserSessionData userSessionData; | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| package org.owasp.webgoat.container.service; | package org.owasp.webgoat.container.report; | ||||||
| 
 | 
 | ||||||
| import static org.hamcrest.CoreMatchers.is; | import static org.hamcrest.CoreMatchers.is; | ||||||
| import static org.mockito.ArgumentMatchers.any; | import static org.mockito.ArgumentMatchers.any; | ||||||
| @ -18,22 +18,23 @@ import org.owasp.webgoat.container.i18n.PluginMessages; | |||||||
| import org.owasp.webgoat.container.lessons.Lesson; | import org.owasp.webgoat.container.lessons.Lesson; | ||||||
| import org.owasp.webgoat.container.session.Course; | import org.owasp.webgoat.container.session.Course; | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.LessonTracker; | import org.owasp.webgoat.container.users.LessonProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.security.test.context.support.WithMockUser; | import org.springframework.security.test.context.support.WithMockUser; | ||||||
| import org.springframework.test.web.servlet.MockMvc; | import org.springframework.test.web.servlet.MockMvc; | ||||||
| import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||||||
| 
 | 
 | ||||||
| @ExtendWith(MockitoExtension.class) | @ExtendWith(MockitoExtension.class) | ||||||
| public class ReportCardServiceTest { | // TODO: Rewrite this as end-to-end test this mocks too many classes | ||||||
|  | public class ReportCardControllerTest { | ||||||
| 
 | 
 | ||||||
|   private MockMvc mockMvc; |   private MockMvc mockMvc; | ||||||
|   @Mock private Course course; |   @Mock private Course course; | ||||||
|   @Mock private UserTracker userTracker; |   @Mock private UserProgress userTracker; | ||||||
|   @Mock private Lesson lesson; |   @Mock private Lesson lesson; | ||||||
|   @Mock private LessonTracker lessonTracker; |   @Mock private LessonProgress lessonTracker; | ||||||
|   @Mock private UserTrackerRepository userTrackerRepository; |   @Mock private UserProgressRepository userTrackerRepository; | ||||||
|   @Mock private WebSession websession; |   @Mock private WebSession websession; | ||||||
|   @Mock private PluginMessages pluginMessages; |   @Mock private PluginMessages pluginMessages; | ||||||
| 
 | 
 | ||||||
| @ -41,7 +42,7 @@ public class ReportCardServiceTest { | |||||||
|   void setup() { |   void setup() { | ||||||
|     this.mockMvc = |     this.mockMvc = | ||||||
|         standaloneSetup( |         standaloneSetup( | ||||||
|                 new ReportCardService(websession, userTrackerRepository, course, pluginMessages)) |                 new ReportCardController(websession, userTrackerRepository, course, pluginMessages)) | ||||||
|             .build(); |             .build(); | ||||||
|     when(pluginMessages.getMessage(anyString())).thenReturn("Test"); |     when(pluginMessages.getMessage(anyString())).thenReturn("Test"); | ||||||
|   } |   } | ||||||
| @ -54,12 +55,11 @@ public class ReportCardServiceTest { | |||||||
|     when(course.getTotalOfAssignments()).thenReturn(10); |     when(course.getTotalOfAssignments()).thenReturn(10); | ||||||
|     when(course.getLessons()).thenAnswer(x -> List.of(lesson)); |     when(course.getLessons()).thenAnswer(x -> List.of(lesson)); | ||||||
|     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); |     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); | ||||||
|     when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); |     when(userTracker.getLessonProgress(any(Lesson.class))).thenReturn(lessonTracker); | ||||||
|     mockMvc |     mockMvc | ||||||
|         .perform(MockMvcRequestBuilders.get("/service/reportcard.mvc")) |         .perform(MockMvcRequestBuilders.get("/service/reportcard.mvc")) | ||||||
|         .andExpect(status().isOk()) |         .andExpect(status().isOk()) | ||||||
|         .andExpect(jsonPath("$.totalNumberOfLessons", is(1))) |         .andExpect(jsonPath("$.totalNumberOfLessons", is(1))) | ||||||
|         .andExpect(jsonPath("$.solvedLessons", is(0))) |  | ||||||
|         .andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0))) |         .andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0))) | ||||||
|         .andExpect(jsonPath("$.totalNumberOfAssignments", is(10))) |         .andExpect(jsonPath("$.totalNumberOfAssignments", is(10))) | ||||||
|         .andExpect(jsonPath("$.lessonStatistics[0].name", is("Test"))) |         .andExpect(jsonPath("$.lessonStatistics[0].name", is("Test"))) | ||||||
| @ -41,9 +41,9 @@ import org.owasp.webgoat.container.lessons.Category; | |||||||
| import org.owasp.webgoat.container.lessons.Lesson; | import org.owasp.webgoat.container.lessons.Lesson; | ||||||
| import org.owasp.webgoat.container.session.Course; | import org.owasp.webgoat.container.session.Course; | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.LessonTracker; | import org.owasp.webgoat.container.users.LessonProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.test.web.servlet.MockMvc; | import org.springframework.test.web.servlet.MockMvc; | ||||||
| import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||||||
|  |  | ||||||
| @ -51,11 +51,11 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | |||||||
| public class LessonMenuServiceTest { | public class LessonMenuServiceTest { | ||||||
|  |  | ||||||
|   @Mock(lenient = true) |   @Mock(lenient = true) | ||||||
|   private LessonTracker lessonTracker; |   private LessonProgress lessonTracker; | ||||||
|  |  | ||||||
|   @Mock private Course course; |   @Mock private Course course; | ||||||
|   @Mock private UserTracker userTracker; |   @Mock private UserProgress userTracker; | ||||||
|   @Mock private UserTrackerRepository userTrackerRepository; |   @Mock private UserProgressRepository userTrackerRepository; | ||||||
|   @Mock private WebSession webSession; |   @Mock private WebSession webSession; | ||||||
|   private MockMvc mockMvc; |   private MockMvc mockMvc; | ||||||
|  |  | ||||||
| @ -81,7 +81,7 @@ public class LessonMenuServiceTest { | |||||||
|     when(lessonTracker.isLessonSolved()).thenReturn(false); |     when(lessonTracker.isLessonSolved()).thenReturn(false); | ||||||
|     when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2)); |     when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2)); | ||||||
|     when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); |     when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); | ||||||
|     when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); |     when(userTracker.getLessonProgress(any(Lesson.class))).thenReturn(lessonTracker); | ||||||
|     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); |     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); | ||||||
|  |  | ||||||
|     mockMvc |     mockMvc | ||||||
| @ -98,7 +98,7 @@ public class LessonMenuServiceTest { | |||||||
|     when(lessonTracker.isLessonSolved()).thenReturn(true); |     when(lessonTracker.isLessonSolved()).thenReturn(true); | ||||||
|     when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1)); |     when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1)); | ||||||
|     when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); |     when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); | ||||||
|     when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); |     when(userTracker.getLessonProgress(any(Lesson.class))).thenReturn(lessonTracker); | ||||||
|     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); |     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); | ||||||
|  |  | ||||||
|     mockMvc |     mockMvc | ||||||
|  | |||||||
| @ -16,9 +16,9 @@ import org.mockito.junit.jupiter.MockitoExtension; | |||||||
| import org.owasp.webgoat.container.lessons.Assignment; | import org.owasp.webgoat.container.lessons.Assignment; | ||||||
| import org.owasp.webgoat.container.lessons.Lesson; | import org.owasp.webgoat.container.lessons.Lesson; | ||||||
| import org.owasp.webgoat.container.session.WebSession; | import org.owasp.webgoat.container.session.WebSession; | ||||||
| import org.owasp.webgoat.container.users.LessonTracker; | import org.owasp.webgoat.container.users.LessonProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTracker; | import org.owasp.webgoat.container.users.UserProgress; | ||||||
| import org.owasp.webgoat.container.users.UserTrackerRepository; | import org.owasp.webgoat.container.users.UserProgressRepository; | ||||||
| import org.springframework.http.MediaType; | import org.springframework.http.MediaType; | ||||||
| import org.springframework.test.web.servlet.MockMvc; | import org.springframework.test.web.servlet.MockMvc; | ||||||
| import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||||||
| @ -60,16 +60,16 @@ class LessonProgressServiceTest { | |||||||
|   private MockMvc mockMvc; |   private MockMvc mockMvc; | ||||||
|  |  | ||||||
|   @Mock private Lesson lesson; |   @Mock private Lesson lesson; | ||||||
|   @Mock private UserTracker userTracker; |   @Mock private UserProgress userTracker; | ||||||
|   @Mock private LessonTracker lessonTracker; |   @Mock private LessonProgress lessonTracker; | ||||||
|   @Mock private UserTrackerRepository userTrackerRepository; |   @Mock private UserProgressRepository userTrackerRepository; | ||||||
|   @Mock private WebSession websession; |   @Mock private WebSession websession; | ||||||
|  |  | ||||||
|   @BeforeEach |   @BeforeEach | ||||||
|   void setup() { |   void setup() { | ||||||
|     Assignment assignment = new Assignment("test", "test", List.of()); |     Assignment assignment = new Assignment("test", "test", List.of()); | ||||||
|     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); |     when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); | ||||||
|     when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); |     when(userTracker.getLessonProgress(any(Lesson.class))).thenReturn(lessonTracker); | ||||||
|     when(websession.getCurrentLesson()).thenReturn(lesson); |     when(websession.getCurrentLesson()).thenReturn(lesson); | ||||||
|     when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true)); |     when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true)); | ||||||
|     this.mockMvc = |     this.mockMvc = | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ import org.assertj.core.api.Assertions; | |||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| import org.owasp.webgoat.container.lessons.Assignment; | import org.owasp.webgoat.container.lessons.Assignment; | ||||||
| import org.owasp.webgoat.container.lessons.Lesson; | import org.owasp.webgoat.container.lessons.Lesson; | ||||||
| import org.owasp.webgoat.container.users.LessonTracker; | import org.owasp.webgoat.container.users.LessonProgress; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * ************************************************************************************************ |  * ************************************************************************************************ | ||||||
| @ -49,7 +49,7 @@ class LessonTrackerTest { | |||||||
|     Lesson lesson = mock(Lesson.class); |     Lesson lesson = mock(Lesson.class); | ||||||
|     when(lesson.getAssignments()) |     when(lesson.getAssignments()) | ||||||
|         .thenReturn(List.of(new Assignment("assignment", "assignment", List.of("")))); |         .thenReturn(List.of(new Assignment("assignment", "assignment", List.of("")))); | ||||||
|     LessonTracker lessonTracker = new LessonTracker(lesson); |     LessonProgress lessonTracker = new LessonProgress(lesson); | ||||||
|     lessonTracker.assignmentSolved("assignment"); |     lessonTracker.assignmentSolved("assignment"); | ||||||
|  |  | ||||||
|     Assertions.assertThat(lessonTracker.isLessonSolved()).isTrue(); |     Assertions.assertThat(lessonTracker.isLessonSolved()).isTrue(); | ||||||
| @ -62,7 +62,7 @@ class LessonTrackerTest { | |||||||
|     Assignment a2 = new Assignment("a2"); |     Assignment a2 = new Assignment("a2"); | ||||||
|     List<Assignment> assignments = List.of(a1, a2); |     List<Assignment> assignments = List.of(a1, a2); | ||||||
|     when(lesson.getAssignments()).thenReturn(assignments); |     when(lesson.getAssignments()).thenReturn(assignments); | ||||||
|     LessonTracker lessonTracker = new LessonTracker(lesson); |     LessonProgress lessonTracker = new LessonProgress(lesson); | ||||||
|     lessonTracker.assignmentSolved("a1"); |     lessonTracker.assignmentSolved("a1"); | ||||||
|  |  | ||||||
|     Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview(); |     Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview(); | ||||||
| @ -76,7 +76,7 @@ class LessonTrackerTest { | |||||||
|     Assignment a1 = new Assignment("a1"); |     Assignment a1 = new Assignment("a1"); | ||||||
|     List<Assignment> assignments = List.of(a1); |     List<Assignment> assignments = List.of(a1); | ||||||
|     when(lesson.getAssignments()).thenReturn(assignments); |     when(lesson.getAssignments()).thenReturn(assignments); | ||||||
|     LessonTracker lessonTracker = new LessonTracker(lesson); |     LessonProgress lessonTracker = new LessonProgress(lesson); | ||||||
|     lessonTracker.assignmentSolved("a1"); |     lessonTracker.assignmentSolved("a1"); | ||||||
|     lessonTracker.assignmentSolved("a1"); |     lessonTracker.assignmentSolved("a1"); | ||||||
|  |  | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; | |||||||
| class UserServiceTest { | class UserServiceTest { | ||||||
|  |  | ||||||
|   @Mock private UserRepository userRepository; |   @Mock private UserRepository userRepository; | ||||||
|   @Mock private UserTrackerRepository userTrackerRepository; |   @Mock private UserProgressRepository userTrackerRepository; | ||||||
|   @Mock private JdbcTemplate jdbcTemplate; |   @Mock private JdbcTemplate jdbcTemplate; | ||||||
|   @Mock private Function<String, Flyway> flywayLessons; |   @Mock private Function<String, Flyway> flywayLessons; | ||||||
|  |  | ||||||
|  | |||||||
| @ -34,23 +34,23 @@ class UserTrackerRepositoryTest { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Autowired private UserTrackerRepository userTrackerRepository; |   @Autowired private UserProgressRepository userTrackerRepository; | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
|   void saveUserTracker() { |   void saveUserTracker() { | ||||||
|     UserTracker userTracker = new UserTracker("test"); |     UserProgress userTracker = new UserProgress("test"); | ||||||
|  |  | ||||||
|     userTrackerRepository.save(userTracker); |     userTrackerRepository.save(userTracker); | ||||||
|  |  | ||||||
|     userTracker = userTrackerRepository.findByUser("test"); |     userTracker = userTrackerRepository.findByUser("test"); | ||||||
|     Assertions.assertThat(userTracker.getLessonTracker("test")).isNotNull(); |     Assertions.assertThat(userTracker.getLessonProgress("test")).isNotNull(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
|   void solvedAssignmentsShouldBeSaved() { |   void solvedAssignmentsShouldBeSaved() { | ||||||
|     UserTracker userTracker = new UserTracker("test"); |     UserProgress userTracker = new UserProgress("test"); | ||||||
|     TestLesson lesson = new TestLesson(); |     TestLesson lesson = new TestLesson(); | ||||||
|     userTracker.getLessonTracker(lesson); |     userTracker.getLessonProgress(lesson); | ||||||
|     userTracker.assignmentFailed(lesson); |     userTracker.assignmentFailed(lesson); | ||||||
|     userTracker.assignmentFailed(lesson); |     userTracker.assignmentFailed(lesson); | ||||||
|     userTracker.assignmentSolved(lesson, "test"); |     userTracker.assignmentSolved(lesson, "test"); | ||||||
| @ -63,9 +63,9 @@ class UserTrackerRepositoryTest { | |||||||
|  |  | ||||||
|   @Test |   @Test | ||||||
|   void saveAndLoadShouldHaveCorrectNumberOfAttempts() { |   void saveAndLoadShouldHaveCorrectNumberOfAttempts() { | ||||||
|     UserTracker userTracker = new UserTracker("test"); |     UserProgress userTracker = new UserProgress("test"); | ||||||
|     TestLesson lesson = new TestLesson(); |     TestLesson lesson = new TestLesson(); | ||||||
|     userTracker.getLessonTracker(lesson); |     userTracker.getLessonProgress(lesson); | ||||||
|     userTracker.assignmentFailed(lesson); |     userTracker.assignmentFailed(lesson); | ||||||
|     userTracker.assignmentFailed(lesson); |     userTracker.assignmentFailed(lesson); | ||||||
|     userTrackerRepository.saveAndFlush(userTracker); |     userTrackerRepository.saveAndFlush(userTracker); | ||||||
| @ -75,6 +75,6 @@ class UserTrackerRepositoryTest { | |||||||
|     userTracker.assignmentFailed(lesson); |     userTracker.assignmentFailed(lesson); | ||||||
|     userTrackerRepository.saveAndFlush(userTracker); |     userTrackerRepository.saveAndFlush(userTracker); | ||||||
|  |  | ||||||
|     Assertions.assertThat(userTracker.getLessonTracker(lesson).getNumberOfAttempts()).isEqualTo(4); |     Assertions.assertThat(userTracker.getLessonProgress(lesson).getNumberOfAttempts()).isEqualTo(4); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user