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:
Nanne Baars 2024-07-09 20:07:09 +02:00 committed by GitHub
parent 1531987da5
commit a0b6decf34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 237 additions and 248 deletions

View File

@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
java-version: [ 17, 21 ]
java-version: [ 21 ]
steps:
- uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.java-version }}

View File

@ -5,7 +5,7 @@ on:
- '.txt'
- 'LICENSE'
- 'docs/**'
branches: [main]
branches: [ main ]
push:
branches:
- main
@ -14,8 +14,10 @@ jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
os: [ windows-latest, ubuntu-latest, macos-13 ]
max-parallel: 1
steps:
- uses: actions/checkout@v4.1.6
- name: Set up JDK 21
@ -31,16 +33,4 @@ jobs:
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2-
- name: Build with Maven
run: |
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
run: mvn --no-transfer-progress verify

View File

View File

@ -669,10 +669,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -23,8 +23,8 @@
package org.owasp.webgoat.container.assignments;
import org.owasp.webgoat.container.session.WebSession;
import org.owasp.webgoat.container.users.UserTracker;
import org.owasp.webgoat.container.users.UserTrackerRepository;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
@ -36,11 +36,11 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice
public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
private UserTrackerRepository userTrackerRepository;
private UserProgressRepository userTrackerRepository;
private WebSession webSession;
public LessonTrackerInterceptor(
UserTrackerRepository userTrackerRepository, WebSession webSession) {
UserProgressRepository userTrackerRepository, WebSession webSession) {
this.userTrackerRepository = userTrackerRepository;
this.webSession = webSession;
}
@ -66,9 +66,9 @@ public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
}
protected AttackResult trackProgress(AttackResult attackResult) {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
UserProgress userTracker = userTrackerRepository.findByUser(webSession.getUserName());
if (userTracker == null) {
userTracker = new UserTracker(webSession.getUserName());
userTracker = new UserProgress(webSession.getUserName());
}
if (attackResult.assignmentSolved()) {
userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment());

View File

@ -54,7 +54,7 @@ public class Assignment {
@Transient private List<String> hints;
private Assignment() {
protected Assignment() {
// Hibernate
}

View File

@ -0,0 +1,3 @@
package org.owasp.webgoat.container.report;
record LessonStatistics(String name, boolean solved, int numberOfAttempts) {}

View File

@ -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) {}
}

View File

@ -39,9 +39,9 @@ import org.owasp.webgoat.container.lessons.LessonMenuItem;
import org.owasp.webgoat.container.lessons.LessonMenuItemType;
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.owasp.webgoat.container.users.LessonProgress;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@ -60,7 +60,7 @@ public class LessonMenuService {
public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc";
private final Course course;
private final WebSession webSession;
private UserTrackerRepository userTrackerRepository;
private UserProgressRepository userTrackerRepository;
@Value("#{'${exclude.categories}'.split(',')}")
private List<String> excludeCategories;
@ -77,7 +77,7 @@ public class LessonMenuService {
public @ResponseBody List<LessonMenuItem> showLeftNav() {
List<LessonMenuItem> menu = new ArrayList<>();
List<Category> categories = course.getCategories();
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
UserProgress userTracker = userTrackerRepository.findByUser(webSession.getUserName());
for (Category category : categories) {
if (excludeCategories.contains(category.name())) {
@ -97,7 +97,7 @@ public class LessonMenuService {
lessonItem.setName(lesson.getTitle());
lessonItem.setLink(lesson.getLink());
lessonItem.setType(LessonMenuItemType.LESSON);
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
LessonProgress lessonTracker = userTracker.getLessonProgress(lesson);
boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
lessonItem.setComplete(lessonSolved);
categoryItem.addChild(lessonItem);

View File

@ -6,7 +6,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.owasp.webgoat.container.lessons.Assignment;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@ -20,7 +20,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
@RequiredArgsConstructor
public class LessonProgressService {
private final UserTrackerRepository userTrackerRepository;
private final UserProgressRepository userTrackerRepository;
private final WebSession webSession;
/**
@ -36,7 +36,7 @@ public class LessonProgressService {
var currentLesson = webSession.getCurrentLesson();
if (currentLesson != null) {
var lessonTracker = userTracker.getLessonTracker(currentLesson);
var lessonTracker = userTracker.getLessonProgress(currentLesson);
return lessonTracker.getLessonOverview().entrySet().stream()
.map(entry -> new LessonOverview(entry.getKey(), entry.getValue()))
.toList();

View File

@ -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;
}
}

View File

@ -32,8 +32,8 @@ import org.flywaydb.core.Flyway;
import org.owasp.webgoat.container.lessons.Initializeable;
import org.owasp.webgoat.container.lessons.Lesson;
import org.owasp.webgoat.container.session.WebSession;
import org.owasp.webgoat.container.users.UserTracker;
import org.owasp.webgoat.container.users.UserTrackerRepository;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@ -45,7 +45,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
public class RestartLessonService {
private final WebSession webSession;
private final UserTrackerRepository userTrackerRepository;
private final UserProgressRepository userTrackerRepository;
private final Function<String, Flyway> flywayLessons;
private final List<Initializeable> lessonsToInitialize;
@ -55,7 +55,7 @@ public class RestartLessonService {
Lesson al = webSession.getCurrentLesson();
log.debug("Restarting lesson: " + al);
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
UserProgress userTracker = userTrackerRepository.findByUser(webSession.getUserName());
userTracker.reset(al);
userTrackerRepository.save(userTracker);

View File

@ -52,7 +52,7 @@ import org.owasp.webgoat.container.lessons.Lesson;
*/
@Entity
@EqualsAndHashCode
public class LessonTracker {
public class LessonProgress {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ -69,11 +69,11 @@ public class LessonTracker {
@Getter private int numberOfAttempts = 0;
@Version private Integer version;
private LessonTracker() {
protected LessonProgress() {
// JPA
}
public LessonTracker(Lesson lesson) {
public LessonProgress(Lesson lesson) {
lessonName = lesson.getId();
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)));
return overview;
}
long numberOfSolvedAssignments() {
return solvedAssignments.size();
}
}

View File

@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
@AllArgsConstructor
public class Scoreboard {
private final UserTrackerRepository userTrackerRepository;
private final UserProgressRepository userTrackerRepository;
private final UserRepository userRepository;
private final Course course;
private final PluginMessages pluginMessages;
@ -46,7 +46,7 @@ public class Scoreboard {
.collect(Collectors.toList());
}
private List<String> challengesSolved(UserTracker userTracker) {
private List<String> challengesSolved(UserProgress userTracker) {
List<String> challenges =
List.of(
"Challenge1",
@ -59,10 +59,10 @@ public class Scoreboard {
"Challenge8",
"Challenge9");
return challenges.stream()
.map(userTracker::getLessonTracker)
.map(userTracker::getLessonProgress)
.flatMap(Optional::stream)
.filter(LessonTracker::isLessonSolved)
.map(LessonTracker::getLessonName)
.filter(LessonProgress::isLessonSolved)
.map(LessonProgress::getLessonName)
.map(this::toLessonTitle)
.toList();
}

View File

@ -9,13 +9,10 @@ import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.lessons.Assignment;
import org.owasp.webgoat.container.lessons.Lesson;
/**
@ -52,7 +49,7 @@ import org.owasp.webgoat.container.lessons.Lesson;
@Slf4j
@Entity
@EqualsAndHashCode
public class UserTracker {
public class UserProgress {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ -62,11 +59,11 @@ public class UserTracker {
private String user;
@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;
}
@ -76,15 +73,15 @@ public class UserTracker {
* @param lesson the lesson
* @return a lesson tracker created if not already present
*/
public LessonTracker getLessonTracker(Lesson lesson) {
Optional<LessonTracker> lessonTracker =
lessonTrackers.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
if (!lessonTracker.isPresent()) {
LessonTracker newLessonTracker = new LessonTracker(lesson);
lessonTrackers.add(newLessonTracker);
public LessonProgress getLessonProgress(Lesson lesson) {
Optional<LessonProgress> progress =
lessonProgress.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
if (!progress.isPresent()) {
LessonProgress newLessonTracker = new LessonProgress(lesson);
lessonProgress.add(newLessonTracker);
return newLessonTracker;
} else {
return lessonTracker.get();
return progress.get();
}
}
@ -94,43 +91,34 @@ public class UserTracker {
* @param id the id of the lesson
* @return optional due to the fact we can only create a lesson tracker based on a lesson
*/
public Optional<LessonTracker> getLessonTracker(String id) {
return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
public Optional<LessonProgress> getLessonProgress(String id) {
return lessonProgress.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
}
public void assignmentSolved(Lesson lesson, String assignmentName) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
lessonTracker.assignmentSolved(assignmentName);
LessonProgress progress = getLessonProgress(lesson);
progress.incrementAttempts();
progress.assignmentSolved(assignmentName);
}
public void assignmentFailed(Lesson lesson) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
LessonProgress progress = getLessonProgress(lesson);
progress.incrementAttempts();
}
public void reset(Lesson al) {
LessonTracker lessonTracker = getLessonTracker(al);
lessonTracker.reset();
LessonProgress progress = getLessonProgress(al);
progress.reset();
}
public int numberOfLessonsSolved() {
int numberOfLessonsSolved = 0;
for (LessonTracker lessonTracker : lessonTrackers) {
if (lessonTracker.isLessonSolved()) {
numberOfLessonsSolved = numberOfLessonsSolved + 1;
}
}
return numberOfLessonsSolved;
public long numberOfLessonsSolved() {
return lessonProgress.stream().filter(LessonProgress::isLessonSolved).count();
}
public int numberOfAssignmentsSolved() {
int numberOfAssignmentsSolved = 0;
for (LessonTracker lessonTracker : lessonTrackers) {
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
numberOfAssignmentsSolved =
lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
}
return numberOfAssignmentsSolved;
public long numberOfAssignmentsSolved() {
return lessonProgress.stream()
.map(LessonProgress::numberOfSolvedAssignments)
.mapToLong(Long::valueOf)
.sum();
}
}

View File

@ -6,7 +6,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
* @author nbaars
* @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);
}

View File

@ -19,7 +19,7 @@ import org.springframework.stereotype.Service;
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final UserTrackerRepository userTrackerRepository;
private final UserProgressRepository userTrackerRepository;
private final JdbcTemplate jdbcTemplate;
private final Function<String, Flyway> flywayLessons;
private final List<Initializeable> lessonInitializables;
@ -43,7 +43,7 @@ public class UserService implements UserDetailsService {
if (!userAlreadyExists) {
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);
}
}

View File

@ -26,8 +26,8 @@ import jakarta.servlet.http.HttpServletRequest;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.users.UserTracker;
import org.owasp.webgoat.container.users.UserTrackerRepository;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
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"})
public class CSRFLogin extends AssignmentEndpoint {
private final UserTrackerRepository userTrackerRepository;
private final UserProgressRepository userTrackerRepository;
public CSRFLogin(UserTrackerRepository userTrackerRepository) {
public CSRFLogin(UserProgressRepository userTrackerRepository) {
this.userTrackerRepository = userTrackerRepository;
}
@ -60,7 +60,7 @@ public class CSRFLogin extends AssignmentEndpoint {
}
private void markAssignmentSolvedWithRealUser(String username) {
UserTracker userTracker = userTrackerRepository.findByUser(username);
UserProgress userTracker = userTrackerRepository.findByUser(username);
userTracker.assignmentSolved(
getWebSession().getCurrentLesson(), this.getClass().getSimpleName());
userTrackerRepository.save(userTracker);

View 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;

View File

@ -8,8 +8,7 @@ define(['jquery',
'goatApp/support/GoatUtils',
'goatApp/view/UserAndInfoView',
'goatApp/view/MenuButtonView',
'goatApp/model/LessonInfoModel',
'goatApp/view/TitleView'
'goatApp/model/LessonInfoModel'
],
function($,
_,
@ -21,8 +20,7 @@ define(['jquery',
GoatUtils,
UserAndInfoView,
MenuButtonView,
LessonInfoModel,
TitleView
LessonInfoModel
) {
'use strict'

View File

@ -32,8 +32,8 @@ import org.owasp.webgoat.container.i18n.Messages;
import org.owasp.webgoat.container.i18n.PluginMessages;
import org.owasp.webgoat.container.session.UserSessionData;
import org.owasp.webgoat.container.session.WebSession;
import org.owasp.webgoat.container.users.UserTracker;
import org.owasp.webgoat.container.users.UserTrackerRepository;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.util.ReflectionTestUtils;
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
public class AssignmentEndpointTest {
@Mock protected UserTracker userTracker;
@Mock protected UserTrackerRepository userTrackerRepository;
@Mock protected UserProgress userTracker;
@Mock protected UserProgressRepository userTrackerRepository;
@Mock protected WebSession webSession;
@Mock protected UserSessionData userSessionData;

View File

@ -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.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.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.owasp.webgoat.container.users.LessonProgress;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@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;
@Mock private Course course;
@Mock private UserTracker userTracker;
@Mock private UserProgress userTracker;
@Mock private Lesson lesson;
@Mock private LessonTracker lessonTracker;
@Mock private UserTrackerRepository userTrackerRepository;
@Mock private LessonProgress lessonTracker;
@Mock private UserProgressRepository userTrackerRepository;
@Mock private WebSession websession;
@Mock private PluginMessages pluginMessages;
@ -41,7 +42,7 @@ public class ReportCardServiceTest {
void setup() {
this.mockMvc =
standaloneSetup(
new ReportCardService(websession, userTrackerRepository, course, pluginMessages))
new ReportCardController(websession, userTrackerRepository, course, pluginMessages))
.build();
when(pluginMessages.getMessage(anyString())).thenReturn("Test");
}
@ -54,12 +55,11 @@ public class ReportCardServiceTest {
when(course.getTotalOfAssignments()).thenReturn(10);
when(course.getLessons()).thenAnswer(x -> List.of(lesson));
when(userTrackerRepository.findByUser(any())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker);
when(userTracker.getLessonProgress(any(Lesson.class))).thenReturn(lessonTracker);
mockMvc
.perform(MockMvcRequestBuilders.get("/service/reportcard.mvc"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.totalNumberOfLessons", is(1)))
.andExpect(jsonPath("$.solvedLessons", is(0)))
.andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0)))
.andExpect(jsonPath("$.totalNumberOfAssignments", is(10)))
.andExpect(jsonPath("$.lessonStatistics[0].name", is("Test")))

View File

@ -41,9 +41,9 @@ import org.owasp.webgoat.container.lessons.Category;
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.owasp.webgoat.container.users.LessonProgress;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@ -51,11 +51,11 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
public class LessonMenuServiceTest {
@Mock(lenient = true)
private LessonTracker lessonTracker;
private LessonProgress lessonTracker;
@Mock private Course course;
@Mock private UserTracker userTracker;
@Mock private UserTrackerRepository userTrackerRepository;
@Mock private UserProgress userTracker;
@Mock private UserProgressRepository userTrackerRepository;
@Mock private WebSession webSession;
private MockMvc mockMvc;
@ -81,7 +81,7 @@ public class LessonMenuServiceTest {
when(lessonTracker.isLessonSolved()).thenReturn(false);
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2));
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);
mockMvc
@ -98,7 +98,7 @@ public class LessonMenuServiceTest {
when(lessonTracker.isLessonSolved()).thenReturn(true);
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1));
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);
mockMvc

View File

@ -16,9 +16,9 @@ import org.mockito.junit.jupiter.MockitoExtension;
import org.owasp.webgoat.container.lessons.Assignment;
import org.owasp.webgoat.container.lessons.Lesson;
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.owasp.webgoat.container.users.LessonProgress;
import org.owasp.webgoat.container.users.UserProgress;
import org.owasp.webgoat.container.users.UserProgressRepository;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@ -60,16 +60,16 @@ class LessonProgressServiceTest {
private MockMvc mockMvc;
@Mock private Lesson lesson;
@Mock private UserTracker userTracker;
@Mock private LessonTracker lessonTracker;
@Mock private UserTrackerRepository userTrackerRepository;
@Mock private UserProgress userTracker;
@Mock private LessonProgress lessonTracker;
@Mock private UserProgressRepository userTrackerRepository;
@Mock private WebSession websession;
@BeforeEach
void setup() {
Assignment assignment = new Assignment("test", "test", List.of());
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(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true));
this.mockMvc =

View File

@ -10,7 +10,7 @@ import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.owasp.webgoat.container.lessons.Assignment;
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);
when(lesson.getAssignments())
.thenReturn(List.of(new Assignment("assignment", "assignment", List.of(""))));
LessonTracker lessonTracker = new LessonTracker(lesson);
LessonProgress lessonTracker = new LessonProgress(lesson);
lessonTracker.assignmentSolved("assignment");
Assertions.assertThat(lessonTracker.isLessonSolved()).isTrue();
@ -62,7 +62,7 @@ class LessonTrackerTest {
Assignment a2 = new Assignment("a2");
List<Assignment> assignments = List.of(a1, a2);
when(lesson.getAssignments()).thenReturn(assignments);
LessonTracker lessonTracker = new LessonTracker(lesson);
LessonProgress lessonTracker = new LessonProgress(lesson);
lessonTracker.assignmentSolved("a1");
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
@ -76,7 +76,7 @@ class LessonTrackerTest {
Assignment a1 = new Assignment("a1");
List<Assignment> assignments = List.of(a1);
when(lesson.getAssignments()).thenReturn(assignments);
LessonTracker lessonTracker = new LessonTracker(lesson);
LessonProgress lessonTracker = new LessonProgress(lesson);
lessonTracker.assignmentSolved("a1");
lessonTracker.assignmentSolved("a1");

View File

@ -18,7 +18,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
class UserServiceTest {
@Mock private UserRepository userRepository;
@Mock private UserTrackerRepository userTrackerRepository;
@Mock private UserProgressRepository userTrackerRepository;
@Mock private JdbcTemplate jdbcTemplate;
@Mock private Function<String, Flyway> flywayLessons;

View File

@ -34,23 +34,23 @@ class UserTrackerRepositoryTest {
}
}
@Autowired private UserTrackerRepository userTrackerRepository;
@Autowired private UserProgressRepository userTrackerRepository;
@Test
void saveUserTracker() {
UserTracker userTracker = new UserTracker("test");
UserProgress userTracker = new UserProgress("test");
userTrackerRepository.save(userTracker);
userTracker = userTrackerRepository.findByUser("test");
Assertions.assertThat(userTracker.getLessonTracker("test")).isNotNull();
Assertions.assertThat(userTracker.getLessonProgress("test")).isNotNull();
}
@Test
void solvedAssignmentsShouldBeSaved() {
UserTracker userTracker = new UserTracker("test");
UserProgress userTracker = new UserProgress("test");
TestLesson lesson = new TestLesson();
userTracker.getLessonTracker(lesson);
userTracker.getLessonProgress(lesson);
userTracker.assignmentFailed(lesson);
userTracker.assignmentFailed(lesson);
userTracker.assignmentSolved(lesson, "test");
@ -63,9 +63,9 @@ class UserTrackerRepositoryTest {
@Test
void saveAndLoadShouldHaveCorrectNumberOfAttempts() {
UserTracker userTracker = new UserTracker("test");
UserProgress userTracker = new UserProgress("test");
TestLesson lesson = new TestLesson();
userTracker.getLessonTracker(lesson);
userTracker.getLessonProgress(lesson);
userTracker.assignmentFailed(lesson);
userTracker.assignmentFailed(lesson);
userTrackerRepository.saveAndFlush(userTracker);
@ -75,6 +75,6 @@ class UserTrackerRepositoryTest {
userTracker.assignmentFailed(lesson);
userTrackerRepository.saveAndFlush(userTracker);
Assertions.assertThat(userTracker.getLessonTracker(lesson).getNumberOfAttempts()).isEqualTo(4);
Assertions.assertThat(userTracker.getLessonProgress(lesson).getNumberOfAttempts()).isEqualTo(4);
}
}