#277 Re-institute admin functionality for WebGoat 8
- Report card functionality is back
This commit is contained in:
parent
490f542885
commit
e2cb9ceae0
@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* *************************************************************************************************
|
||||||
|
* <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 - 20014 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.service;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.Singular;
|
||||||
|
import org.apache.catalina.User;
|
||||||
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
|
import org.owasp.webgoat.session.Course;
|
||||||
|
import org.owasp.webgoat.session.LessonTracker;
|
||||||
|
import org.owasp.webgoat.session.UserTracker;
|
||||||
|
import org.owasp.webgoat.session.WebSession;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>ReportCardService</p>
|
||||||
|
*
|
||||||
|
* @author nbaars
|
||||||
|
* @version $Id: $Id
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class ReportCardService {
|
||||||
|
|
||||||
|
private final UserTracker userTracker;
|
||||||
|
private final Course course;
|
||||||
|
|
||||||
|
public ReportCardService(UserTracker userTracker, Course course) {
|
||||||
|
this.userTracker = userTracker;
|
||||||
|
this.course = course;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
List<AbstractLesson> lessons = course.getLessons();
|
||||||
|
ReportCard reportCard = new ReportCard();
|
||||||
|
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
|
||||||
|
reportCard.setTotalNumberOfAssignments(course.getTotalOfAssignments());
|
||||||
|
reportCard.setNumberOfAssignmentsSolved(userTracker.numberOfAssignmentsSolved());
|
||||||
|
reportCard.setNumberOfLessonsSolved(userTracker.numberOfLessonsSolved());
|
||||||
|
for (AbstractLesson lesson : lessons) {
|
||||||
|
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
|
||||||
|
LessonStatistics lessonStatistics = new LessonStatistics();
|
||||||
|
lessonStatistics.setName(lesson.getTitle());
|
||||||
|
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
|
||||||
|
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
|
||||||
|
reportCard.lessonStatistics.add(lessonStatistics);
|
||||||
|
}
|
||||||
|
return reportCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private class ReportCard {
|
||||||
|
|
||||||
|
private int totalNumberOfLessons;
|
||||||
|
private int totalNumberOfAssignments;
|
||||||
|
private int solvedLessons;
|
||||||
|
private int numberOfAssignmentsSolved;
|
||||||
|
private int numberOfLessonsSolved;
|
||||||
|
private List<LessonStatistics> lessonStatistics = Lists.newArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private class LessonStatistics {
|
||||||
|
private String name;
|
||||||
|
private boolean solved;
|
||||||
|
private int numberOfAttempts;
|
||||||
|
}
|
||||||
|
}
|
@ -89,5 +89,14 @@ public class Course {
|
|||||||
this.lessons = lessons;
|
this.lessons = lessons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTotalOfLessons() {
|
||||||
|
return this.lessons.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalOfAssignments() {
|
||||||
|
final int[] total = {0};
|
||||||
|
this.lessons.stream().forEach(l -> total[0] = total[0] + l.getAssignments().size());
|
||||||
|
return total[0];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,14 @@ package org.owasp.webgoat.session;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
|
import org.owasp.webgoat.lessons.Assignment;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
import org.springframework.util.SerializationUtils;
|
import org.springframework.util.SerializationUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,4 +106,23 @@ public class UserTracker {
|
|||||||
getLessonTracker(al).reset();
|
getLessonTracker(al).reset();
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int numberOfLessonsSolved() {
|
||||||
|
int numberOfLessonsSolved = 0;
|
||||||
|
for(LessonTracker lessonTracker : storage.values()) {
|
||||||
|
if (lessonTracker.isLessonSolved()) {
|
||||||
|
numberOfLessonsSolved = numberOfLessonsSolved + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numberOfLessonsSolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int numberOfAssignmentsSolved() {
|
||||||
|
int numberOfAssignmentsSolved = 0;
|
||||||
|
for (LessonTracker lessonTracker : storage.values()) {
|
||||||
|
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
|
||||||
|
numberOfAssignmentsSolved = lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
|
||||||
|
}
|
||||||
|
return numberOfAssignmentsSolved;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ spring.devtools.restart.enabled=false
|
|||||||
spring.resources.cache-period=0
|
spring.resources.cache-period=0
|
||||||
|
|
||||||
|
|
||||||
webgoat.tracker.overwrite=true
|
webgoat.tracker.overwrite=false
|
||||||
webgoat.user.directory=${user.home}/.webgoat/
|
webgoat.user.directory=${user.home}/.webgoat/
|
||||||
webgoat.build.version=@project.version@
|
webgoat.build.version=@project.version@
|
||||||
webgoat.build.number=@build.number@
|
webgoat.build.number=@build.number@
|
||||||
|
@ -55,9 +55,9 @@ define(['jquery',
|
|||||||
this.lessonOverviewModel = new LessonOverviewModel();
|
this.lessonOverviewModel = new LessonOverviewModel();
|
||||||
this.lessonOverview = new LessonOverviewView(this.lessonOverviewModel);
|
this.lessonOverview = new LessonOverviewView(this.lessonOverviewModel);
|
||||||
this.lessonContentView = options.lessonContentView;
|
this.lessonContentView = options.lessonContentView;
|
||||||
|
this.titleView = options.titleView;
|
||||||
this.developerControlsView = new DeveloperControlsView();
|
this.developerControlsView = new DeveloperControlsView();
|
||||||
|
|
||||||
|
|
||||||
_.extend(Controller.prototype,Backbone.Events);
|
_.extend(Controller.prototype,Backbone.Events);
|
||||||
|
|
||||||
this.start = function() {
|
this.start = function() {
|
||||||
@ -67,12 +67,13 @@ define(['jquery',
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.loadLesson = function(name,pageNum) {
|
this.loadLesson = function(name,pageNum) {
|
||||||
|
|
||||||
if (this.name === name) {
|
if (this.name === name) {
|
||||||
this.lessonContentView.navToPage(pageNum)
|
this.lessonContentView.navToPage(pageNum);
|
||||||
|
this.titleView.render(this.lessonInfoModel.get('lessonTitle'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.titleView = new TitleView();
|
|
||||||
this.helpsLoaded = {};
|
this.helpsLoaded = {};
|
||||||
if (typeof(name) === 'undefined' || name === null) {
|
if (typeof(name) === 'undefined' || name === null) {
|
||||||
//TODO: implement lesson not found or return to welcome page?
|
//TODO: implement lesson not found or return to welcome page?
|
||||||
|
@ -11,22 +11,9 @@ define(['jquery',
|
|||||||
_.extend(Controller.prototype,Backbone.Events);
|
_.extend(Controller.prototype,Backbone.Events);
|
||||||
options = options || {};
|
options = options || {};
|
||||||
this.menuView = options.menuView;
|
this.menuView = options.menuView;
|
||||||
this.titleView = options.titleView;
|
|
||||||
|
|
||||||
// this.initMenu = function() {
|
|
||||||
// this.listenTo(this.menuView,'lesson:click',this.renderTitle);
|
|
||||||
// }
|
|
||||||
|
|
||||||
this.updateMenu = function(){
|
this.updateMenu = function(){
|
||||||
this.menuView.updateMenu();
|
this.menuView.updateMenu();
|
||||||
},
|
|
||||||
|
|
||||||
//TODO: move title rendering into lessonContent/View pipeline once data can support it
|
|
||||||
this.renderTitle = function(title) {
|
|
||||||
this.titleView.render(title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Controller;
|
return Controller;
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
define([
|
||||||
|
'backbone'],
|
||||||
|
function(
|
||||||
|
Backbone) {
|
||||||
|
return Backbone.Model.extend({
|
||||||
|
url: 'service/reportcard.mvc'
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,47 @@
|
|||||||
|
<div class="panel panel-default" style="margin-top:25px">
|
||||||
|
<div class="panel-heading alt"><b>Overview</b></div>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td width="30%">Total number of lessons</td>
|
||||||
|
<td width="70%"><%= totalNumberOfLessons %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="30%">Total number of lessons solved</td>
|
||||||
|
<td width="70%"><%= numberOfLessonsSolved %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="30%">Total number of assignments</td>
|
||||||
|
<td width="70%"><%= totalNumberOfAssignments %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="30%">Total number of assignments solved</td>
|
||||||
|
<td width="70%"><%= numberOfAssignmentsSolved %></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="panel panel-default" style="margin-top:25px">
|
||||||
|
<div class="panel-heading"><b>Lesson overview</b></div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Lesson name</th>
|
||||||
|
<th>Solved</th>
|
||||||
|
<th>Number of attempts</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% _(lessonStatistics).each(function(lesson) { %>
|
||||||
|
<%= lesson.solved ? '<tr class="success">' : '<tr>' %>
|
||||||
|
<td><%= lesson.name %></td>
|
||||||
|
<td><%= lesson.solved %></td>
|
||||||
|
<td><%= lesson.numberOfAttempts %></td>
|
||||||
|
</tr>
|
||||||
|
<% }) %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
@ -5,37 +5,56 @@ define(['jquery',
|
|||||||
'goatApp/controller/MenuController',
|
'goatApp/controller/MenuController',
|
||||||
'goatApp/view/LessonContentView',
|
'goatApp/view/LessonContentView',
|
||||||
'goatApp/view/MenuView',
|
'goatApp/view/MenuView',
|
||||||
'goatApp/view/DeveloperControlsView'
|
'goatApp/view/DeveloperControlsView',
|
||||||
], function ($,
|
'goatApp/view/TitleView'
|
||||||
|
], function ($,
|
||||||
_,
|
_,
|
||||||
Backbone,
|
Backbone,
|
||||||
LessonController,
|
LessonController,
|
||||||
MenuController,
|
MenuController,
|
||||||
LessonContentView,
|
LessonContentView,
|
||||||
MenuView,
|
MenuView,
|
||||||
DeveloperControlsView) {
|
DeveloperControlsView,
|
||||||
|
TitleView) {
|
||||||
|
|
||||||
var lessonContentView = new LessonContentView();
|
var lessonContentView = new LessonContentView();
|
||||||
var menuView = new MenuView();
|
var menuView = new MenuView();
|
||||||
var developerControlsView = new DeveloperControlsView();
|
var developerControlsView = new DeveloperControlsView();
|
||||||
|
var titleView = new TitleView();
|
||||||
|
|
||||||
|
function getContentElement() {
|
||||||
|
return $('#main-content');
|
||||||
|
};
|
||||||
|
|
||||||
|
function render(view) {
|
||||||
|
$('div.pages').hide();
|
||||||
|
//TODO this works for now because we only have one page we should rewrite this a bit
|
||||||
|
if (view != null) {
|
||||||
|
$('#report-card-page').show();
|
||||||
|
} else {
|
||||||
|
$('#lesson-title').show();
|
||||||
|
$('#lesson-page').show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var GoatAppRouter = Backbone.Router.extend({
|
var GoatAppRouter = Backbone.Router.extend({
|
||||||
routes: {
|
routes: {
|
||||||
'welcome':'welcomeRoute',
|
'welcome': 'welcomeRoute',
|
||||||
'lesson/:name':'lessonRoute',
|
'lesson/:name': 'lessonRoute',
|
||||||
'lesson/:name/:pageNum':'lessonPageRoute',
|
'lesson/:name/:pageNum': 'lessonPageRoute',
|
||||||
'test/:param':'testRoute'
|
'test/:param': 'testRoute',
|
||||||
|
'reportCard': 'reportCard'
|
||||||
},
|
},
|
||||||
|
|
||||||
lessonController: new LessonController({
|
lessonController: new LessonController({
|
||||||
lessonContentView: lessonContentView
|
lessonContentView: lessonContentView,
|
||||||
|
titleView: titleView
|
||||||
}),
|
}),
|
||||||
|
|
||||||
menuController: new MenuController({
|
menuController: new MenuController({
|
||||||
menuView: menuView
|
menuView: menuView
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
setUpCustomJS: function () {
|
setUpCustomJS: function () {
|
||||||
webgoat.customjs.jquery = $; //passing jquery into custom js scope ... still klunky, but works for now
|
webgoat.customjs.jquery = $; //passing jquery into custom js scope ... still klunky, but works for now
|
||||||
|
|
||||||
@ -45,18 +64,18 @@ define(['jquery',
|
|||||||
console.log(arguments.callee);
|
console.log(arguments.callee);
|
||||||
//
|
//
|
||||||
webgoat.customjs.jquery.ajax({
|
webgoat.customjs.jquery.ajax({
|
||||||
method:"POST",
|
method: "POST",
|
||||||
url:"/WebGoat/CrossSiteScripting/dom-xss",
|
url: "/WebGoat/CrossSiteScripting/dom-xss",
|
||||||
data:{param1:42,param2:24},
|
data: {param1: 42, param2: 24},
|
||||||
headers:{
|
headers: {
|
||||||
"webgoat-requested-by":"dom-xss-vuln"
|
"webgoat-requested-by": "dom-xss-vuln"
|
||||||
},
|
},
|
||||||
contentType:'application/x-www-form-urlencoded; charset=UTF-8'
|
contentType: 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
init:function() {
|
init: function () {
|
||||||
goatRouter = new GoatAppRouter();
|
goatRouter = new GoatAppRouter();
|
||||||
this.lessonController.start();
|
this.lessonController.start();
|
||||||
// this.menuController.initMenu();
|
// this.menuController.initMenu();
|
||||||
@ -65,39 +84,48 @@ define(['jquery',
|
|||||||
|
|
||||||
this.setUpCustomJS();
|
this.setUpCustomJS();
|
||||||
|
|
||||||
|
goatRouter.on('route:lessonRoute', function (name) {
|
||||||
goatRouter.on('route:lessonRoute', function(name) {
|
render();
|
||||||
this.lessonController.loadLesson(name,0);
|
this.lessonController.loadLesson(name, 0);
|
||||||
//TODO - update menu code from below
|
//TODO - update menu code from below
|
||||||
this.menuController.updateMenu(name);
|
this.menuController.updateMenu(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
goatRouter.on('route:lessonPageRoute', function(name,pageNum) {
|
goatRouter.on('route:lessonPageRoute', function (name, pageNum) {
|
||||||
|
render();
|
||||||
pageNum = (_.isNumber(parseInt(pageNum))) ? parseInt(pageNum) : 0;
|
pageNum = (_.isNumber(parseInt(pageNum))) ? parseInt(pageNum) : 0;
|
||||||
this.lessonController.loadLesson(name,pageNum);
|
this.lessonController.loadLesson(name, pageNum);
|
||||||
//TODO - update menu code from below
|
//TODO - update menu code from below
|
||||||
this.menuController.updateMenu(name);
|
this.menuController.updateMenu(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
goatRouter.on('route:welcomeRoute', function() {
|
goatRouter.on('route:welcomeRoute', function () {
|
||||||
|
render();
|
||||||
this.lessonController.loadWelcome();
|
this.lessonController.loadWelcome();
|
||||||
});
|
});
|
||||||
|
|
||||||
goatRouter.on('route:testRoute', function(param) {
|
goatRouter.on('route:testRoute', function (param) {
|
||||||
|
render();
|
||||||
this.lessonController.testHandler(param);
|
this.lessonController.testHandler(param);
|
||||||
});
|
});
|
||||||
|
|
||||||
goatRouter.on("route", function(route, params) {});
|
goatRouter.on("route", function (route, params) {
|
||||||
|
});
|
||||||
|
|
||||||
Backbone.history.start();
|
Backbone.history.start();
|
||||||
this.listenTo(this.lessonController, 'menu:reload',this.reloadMenu)
|
this.listenTo(this.lessonController, 'menu:reload', this.reloadMenu)
|
||||||
},
|
},
|
||||||
|
|
||||||
reloadMenu: function (curLesson) {
|
reloadMenu: function (curLesson) {
|
||||||
this.menuController.updateMenu();
|
this.menuController.updateMenu();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
|
||||||
|
reportCard : function () {
|
||||||
|
require(['goatApp/view/ReportCardView'], function (ReportCardView) {
|
||||||
|
titleView.render('Report card');
|
||||||
|
render(new ReportCardView());
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return GoatAppRouter;
|
return GoatAppRouter;
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
define(['jquery', 'backbone', 'underscore', 'goatApp/model/ReportCardModel', 'text!templates/report_card.html'],
|
||||||
|
function ($, Backbone, _, ReportCardModel, ReportCardTemplate) {
|
||||||
|
return Backbone.View.extend({
|
||||||
|
el: '#report-card-page',
|
||||||
|
template: ReportCardTemplate,
|
||||||
|
|
||||||
|
initialize: function () {
|
||||||
|
var _this = this;
|
||||||
|
this.model = new ReportCardModel();
|
||||||
|
this.model.fetch().then(function() {
|
||||||
|
_this.render();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
var t = _.template(this.template);
|
||||||
|
this.$el.html(t(this.model.toJSON()));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -16,9 +16,9 @@ require.config({
|
|||||||
jquery: 'libs/jquery-1.10.2.min',
|
jquery: 'libs/jquery-1.10.2.min',
|
||||||
underscore: 'libs/underscore-min',
|
underscore: 'libs/underscore-min',
|
||||||
backbone: 'libs/backbone-min',
|
backbone: 'libs/backbone-min',
|
||||||
templates: 'goatApp/templates'
|
text: 'libs/text',
|
||||||
}
|
templates: 'goatApp/templates',
|
||||||
,
|
},
|
||||||
shim: {
|
shim: {
|
||||||
underscore: {
|
underscore: {
|
||||||
exports: "_"
|
exports: "_"
|
||||||
|
@ -90,6 +90,19 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display:inline" id="settings">
|
||||||
|
<!--<button type="button" id="admin-button" class="btn btn-default right_nav_button" title="Administrator">-->
|
||||||
|
<!--<i class="fa fa-cog"></i>-->
|
||||||
|
<!--</button>-->
|
||||||
|
<button type="button" id="report-card-button" class="btn btn-default right_nav_button button-up"
|
||||||
|
title="Report card">
|
||||||
|
<a href="#reportCard"><i class="fa fa-bar-chart-o"></i></a>
|
||||||
|
</button>
|
||||||
|
<!--<button type="button" id="user-management" class="btn btn-default right_nav_button"-->
|
||||||
|
<!--title="User management">-->
|
||||||
|
<!--<i class="fa fa-users"></i>-->
|
||||||
|
<!--</button>-->
|
||||||
|
</div>
|
||||||
<button type="button" id="about-button" class="btn btn-default right_nav_button" title="About WebGoat"
|
<button type="button" id="about-button" class="btn btn-default right_nav_button" title="About WebGoat"
|
||||||
data-toggle="modal" data-target="#about-modal">
|
data-toggle="modal" data-target="#about-modal">
|
||||||
<i class="fa fa-info"></i>
|
<i class="fa fa-info"></i>
|
||||||
@ -112,6 +125,7 @@
|
|||||||
<!--main content start-->
|
<!--main content start-->
|
||||||
<section class="main-content-wrapper">
|
<section class="main-content-wrapper">
|
||||||
<section id="main-content"> <!--ng-controller="goatLesson"-->
|
<section id="main-content"> <!--ng-controller="goatLesson"-->
|
||||||
|
<div id="lesson-page" class="pages">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<!--<div class="col-md-12" align="left">-->
|
<!--<div class="col-md-12" align="left">-->
|
||||||
@ -122,19 +136,23 @@
|
|||||||
<div id="lesson-content-wrapper" class="panel">
|
<div id="lesson-content-wrapper" class="panel">
|
||||||
<div class="" id="error-notification-container">
|
<div class="" id="error-notification-container">
|
||||||
<div class="" id="error-notification">
|
<div class="" id="error-notification">
|
||||||
<i class="fa fa-exclamation-circle" /> There was an unexpected error. Please try again.
|
<i class="fa fa-exclamation-circle"/> There was an unexpected error. Please try
|
||||||
|
again.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="" id="help-controls">
|
<div class="" id="help-controls">
|
||||||
<button class="btn btn-primary btn-xs btn-danger help-button" id="show-source-button">
|
<button class="btn btn-primary btn-xs btn-danger help-button"
|
||||||
<i class="fa fa-code" />
|
id="show-source-button">
|
||||||
|
<i class="fa fa-code"/>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary btn-xs btn-danger help-button" id="show-hints-button">Show Hints
|
<button class="btn btn-primary btn-xs btn-danger help-button"
|
||||||
|
id="show-hints-button">Show Hints
|
||||||
</button>
|
</button>
|
||||||
<!--<button class="btn btn-primary btn-xs btn-danger help-button" id="show-attack-button">-->
|
<!--<button class="btn btn-primary btn-xs btn-danger help-button" id="show-attack-button">-->
|
||||||
<!--Attack It-->
|
<!--Attack It-->
|
||||||
<!--</button>-->
|
<!--</button>-->
|
||||||
<button class="btn btn-primary btn-xs btn-danger help-button" id="show-lesson-overview-button">Lesson overview
|
<button class="btn btn-primary btn-xs btn-danger help-button"
|
||||||
|
id="show-lesson-overview-button">Lesson overview
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-xs help-button" id="restart-lesson-button">
|
<button class="btn btn-xs help-button" id="restart-lesson-button">
|
||||||
Reset Lesson
|
Reset Lesson
|
||||||
@ -170,9 +188,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="lesson-helps-wrapper" class="panel">
|
<div id="lesson-helps-wrapper" class="panel">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="lesson-help" id="lesson-plan-row">
|
<div class="lesson-help" id="lesson-plan-row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<h4>Lesson Plan</h4>
|
<h4>Lesson Plan</h4>
|
||||||
@ -205,6 +220,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="report-card-page" class="pages" style="display: none;">
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.owasp.webgoat.service;
|
||||||
|
|
||||||
|
import com.beust.jcommander.internal.Lists;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
|
import org.owasp.webgoat.session.Course;
|
||||||
|
import org.owasp.webgoat.session.LessonTracker;
|
||||||
|
import org.owasp.webgoat.session.UserTracker;
|
||||||
|
import org.springframework.security.test.context.support.WithMockUser;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ReportCardServiceTest {
|
||||||
|
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
@Mock
|
||||||
|
private Course course;
|
||||||
|
@Mock
|
||||||
|
private UserTracker userTracker;
|
||||||
|
@Mock
|
||||||
|
private AbstractLesson lesson;
|
||||||
|
@Mock
|
||||||
|
private LessonTracker lessonTracker;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
this.mockMvc = standaloneSetup(new ReportCardService(userTracker, course)).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "guest", password = "guest")
|
||||||
|
public void withLessons() throws Exception {
|
||||||
|
when(lesson.getTitle()).thenReturn("Test");
|
||||||
|
when(course.getTotalOfLessons()).thenReturn(1);
|
||||||
|
when(course.getTotalOfAssignments()).thenReturn(10);
|
||||||
|
when(course.getLessons()).thenReturn(Lists.newArrayList(lesson));
|
||||||
|
when(userTracker.getLessonTracker(any())).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")))
|
||||||
|
.andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0)));
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ -88,4 +89,15 @@ public class UserTrackerTest {
|
|||||||
userTracker.reset(lesson);
|
userTracker.reset(lesson);
|
||||||
assertThat(userTracker.getLessonTracker(lesson).isLessonSolved()).isFalse();
|
assertThat(userTracker.getLessonTracker(lesson).isLessonSolved()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void totalAssignmentsSolved() {
|
||||||
|
UserTracker userTracker = new UserTracker(home.getParent(), "test", false);
|
||||||
|
AbstractLesson lesson = mock(AbstractLesson.class);
|
||||||
|
when(lesson.getAssignments()).thenReturn(Lists.newArrayList(new Assignment("assignment", "assignment")));
|
||||||
|
userTracker.assignmentSolved(lesson, "assignment");
|
||||||
|
|
||||||
|
assertThat(userTracker.numberOfAssignmentsSolved()).isEqualTo(1);
|
||||||
|
assertThat(userTracker.numberOfLessonsSolved()).isEqualTo(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user