Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require_tree .
//= require jquery.nested-fields
// Loads all Bootstrap javascripts
Expand Down
56 changes: 56 additions & 0 deletions app/assets/stylesheets/surveys.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Place all the styles related to the Surveys controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: https://sass-lang.com/

.star-cb-group {
/* remove inline-block whitespace */
font-size: 0;
/* flip the order so we can use the + and ~ combinators */
unicode-bidi: bidi-override;
direction: rtl;
/* the hidden clearer */
}
.star-cb-group * {
font-size: 1rem;
}
.star-cb-group > input {
display: none;
}
.star-cb-group > input + label {
/* only enough room for the star */
display: inline-block;
overflow: hidden;
text-indent: 9999px;
width: 1em;
white-space: nowrap;
cursor: pointer;
}
.star-cb-group > input + label:before {
display: inline-block;
text-indent: -9999px;
content: "☆";
color: #888;
}
.star-cb-group > input:checked ~ label:before, .star-cb-group > input + label:hover ~ label:before, .star-cb-group > input + label:hover:before {
content: "★";
color: rgb(238, 206, 24);
text-shadow: 0 0 1px #333;
}
.star-cb-group > .star-cb-clear + label {
text-indent: -9999px;
width: .5em;
margin-left: -.5em;
}
.star-cb-group > .star-cb-clear + label:before {
width: .5em;
}
.star-cb-group:hover > input + label:before {
content: "☆";
color: #888;
text-shadow: none;
}
.star-cb-group:hover > input + label:hover ~ label:before, .star-cb-group:hover > input + label:hover:before {
content: "★";
color: rgb(238, 206, 24);
text-shadow: 0 0 1px #333;
}
7 changes: 5 additions & 2 deletions app/controllers/challenges_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ def update
@solved_challenge = @flag_found.save_solved_challenge(current_user)
@solved_video_url = @flag_found.video_url
flash.now[:notice] = I18n.t('flag.accepted')
@survey = Survey.new
@survey.submitted_flag_id = @submitted_flag.id
else
flash.now[:alert] = wrong_flag_messages.sample
end
@solvable = @challenge.can_be_solved_by(current_user.team)

render :show
end
Expand All @@ -51,7 +52,9 @@ def find_and_log_flag
flag = params[:challenge]&.[](:submitted_flag) # Safe navigation on a hash
return if flag.nil?

SubmittedFlag.create(user: current_user, challenge: @challenge, text: flag) unless current_user.admin?
unless current_user.admin?
@submitted_flag = SubmittedFlag.create(user: current_user, challenge: @challenge, text: flag)
end
@flag_found = @challenge.find_flag(flag)
end

Expand Down
15 changes: 15 additions & 0 deletions app/controllers/surveys_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class SurveysController < ApplicationController
def create
@survey = Survey.new(survey_params)

redirect_to '/game', notice: I18n.t('surveys.submitted') if @survey.save
end

private

def survey_params
params.require(:survey).permit(:difficulty, :realism, :interest, :comment, :submitted_flag_id)
end
end
1 change: 1 addition & 0 deletions app/models/submitted_flag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class SubmittedFlag < ApplicationRecord
belongs_to :user
belongs_to :challenge
has_one :survey, dependent: :destroy

validates :text, presence: true

Expand Down
5 changes: 5 additions & 0 deletions app/models/survey.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class Survey < ApplicationRecord
belongs_to :submitted_flag, optional: true
end
9 changes: 7 additions & 2 deletions app/views/challenges/show.html.haml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-# For PentestGames, @challenge here can actually be a flag object since Pentest challenges belong to teams + challenges and are linked by a flag object.
-#
-#
- content_for :admin_menu do
%li= link_to t('challenges.admin_edit_challenge', challengename: @challenge.name), admin_edit_url(@challenge)

Expand Down Expand Up @@ -28,7 +28,7 @@
= sanitize(Kramdown::Document.new(@challenge.sponsor_description).to_html)

- if @solvable
= form_for :challenge, url: submit_url(@defense_team, @challenge), method: "put", html: { class: "well", style: "margin-bottom:40px;" } do |f|
= form_for :challenge, url: submit_url(@defense_team, @challenge), method: "put", html: { class: "well form-inline", style: "margin-bottom:40px;" } do |f|
.control-group
%p
= t('challenges.submit_flag')
Expand All @@ -38,6 +38,11 @@
.control-group
= invisible_recaptcha_tags text: 'Submit', :class => "btn btn-primary"

- if @flag_found
%hr/
= render partial: "surveys/form"
%hr/

- if @solved_by.length > 0
%table.table.table-bordered.table-striped
%thead
Expand Down
26 changes: 26 additions & 0 deletions app/views/surveys/_form.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
= form_for @survey, html: { class: "well form-inline", style: "margin-bottom:40px;" } do |f|
- if @survey.errors.any?
#error_explanation
%h2= "#{pluralize(@survey.errors.count, "error")} prohibited this survey from being saved:"
%ul
- @survey.errors.full_messages.each do |message|
%li= message

%h3= t('surveys.new.header')
.rating
.field
= f.label :difficulty
= render partial: "surveys/star_rating", locals: { category: :difficulty, f: f }
.field
= f.label :realism
= render partial: "surveys/star_rating", locals: { category: :realism, f: f }
.field
= f.label :interest
= render partial: "surveys/star_rating", locals: { category: :interest, f: f }
.field
= f.label :comment
= f.text_area :comment
.field
= f.hidden_field :submitted_flag_id
.field
= f.submit t('surveys.new.submit_btn'), class: "btn btn-primary"
5 changes: 5 additions & 0 deletions app/views/surveys/_star_rating.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.rating
%span.star-cb-group
- [5, 4, 3, 2, 1].each do |rating|
= f.radio_button category, rating, { :name => "survey[#{category}]", :id => "#{category}_#{rating}", :value => rating }
%label{:for => "#{category}_#{rating}"}
2 changes: 1 addition & 1 deletion config/initializers/rails_admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
config.actions do
# root actions
dashboard # mandatory
# collection actions
# collection actions
index # mandatory
new do
except ['Challenge', 'FeedItem', 'SolvedChallenge', 'Flag'] # Block users from adding items from their parent classes instead of their own classes
Expand Down
7 changes: 6 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,9 @@ en:
Your account has been locked due to an excessive amount of unsuccessful
sign in attempts.
unlock_line_2: 'Click the link below to unlock your account:'
unlock_account_link: Unlock my account
unlock_account_link: 'Unlock my account'
surveys:
submitted: 'Survey Submitted!'
new:
header: 'Review Solved Challenge'
submit_btn: 'Submit Survey'
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
end
end

resource :surveys, only: %i[create] do
post :create
end

get '/game/summary' => 'games#summary'
get '/game/teams' => 'games#teams'

Expand Down
13 changes: 13 additions & 0 deletions db/migrate/20200710145833_create_surveys.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateSurveys < ActiveRecord::Migration[6.0]
def change
create_table :surveys do |t|
t.integer :difficulty, default: 0, null: false
t.integer :realism, default: 0, null: false
t.integer :interest, default: 0, null: false
t.text :comment, default: "", null: true
t.integer :submitted_flag_id, null: false
t.timestamps
end
add_foreign_key "surveys", "submitted_flags"
end
end
13 changes: 12 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2020_06_23_173255) do
ActiveRecord::Schema.define(version: 2020_07_10_145833) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -178,6 +178,16 @@
t.index ["flag_id"], name: "index_submitted_flags_on_flag_id"
end

create_table "surveys", force: :cascade do |t|
t.integer "difficulty", default: 0, null: false
t.integer "realism", default: 0, null: false
t.integer "interest", default: 0, null: false
t.text "comment", default: ""
t.integer "submitted_flag_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end

create_table "teams", id: :serial, force: :cascade do |t|
t.string "team_name"
t.datetime "created_at"
Expand Down Expand Up @@ -281,5 +291,6 @@
add_foreign_key "challenges", "games"
add_foreign_key "flags", "teams"
add_foreign_key "submitted_flags", "flags"
add_foreign_key "surveys", "submitted_flags"
add_foreign_key "teams", "divisions"
end
22 changes: 22 additions & 0 deletions test/controllers/surveys_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'test_helper'

class SurveysControllerTest < ActionController::TestCase

def setup
create(:active_game)
@team1 = create(:team)
@team2 = create(:team)
@standard_challenge = create(:standard_challenge, flag_count: 3)
@pentest_challenge = create(:pentest_challenge_with_flags)
end

test 'create new survey' do
team_user = create(:user_with_team)
standard_challenge = create(:standard_challenge)
sign_in team_user
submitted_flag = create(:submitted_flag, user: team_user, challenge: standard_challenge)
post :create, params: { survey: { difficulty: 5, realism: 5, interest: 5, comment: "MyText", submitted_flag_id: submitted_flag.id } }
assert_redirected_to game_path
assert_match I18n.t('surveys.submitted'), flash[:notice]
end
end
9 changes: 9 additions & 0 deletions test/factories/surveys.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FactoryBot.define do
factory :survey do
difficulty { 1 }
realism { 1 }
interest { 1 }
comment { "MyText" }
submitted_flag_id { 1 }
end
end
93 changes: 93 additions & 0 deletions test/integration/submitted_flags_survey_display_modes_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
require 'test_helper'

class SubmittedFlagsSurveyDisplayModesTest < ActionDispatch::IntegrationTest
include TeamsHelper
include Devise::Test::IntegrationHelpers

def setup
create(:active_game)
@team1 = create(:team)
@team2 = create(:team)
@standard_challenge = create(:standard_challenge, flag_count: 3)
@pentest_challenge = create(:pentest_challenge_with_flags)
end

test 'solved challenge survey shows for pentest challenge when submitted flag is accepted' do
create(:pentest_solved_challenge, team: @team1, challenge: @pentest_challenge, flag: @team2.defense_flags.first)
sign_in @team1.team_captain
get game_team_challenge_path(@team2, @pentest_challenge)
assert_response :success
if @flag_found
assert_select 'form.well.form-inline' do
assert_select 'h3', I18n.t('surveys.new.header')
assert_select 'div.field', {:count => 3} do
assert_select 'label'
assert_select 'span.star-cb-group'
end
assert_select 'div.field' do
assert_select 'label'
assert_select 'textarea#survey_comment'
end
assert_select 'div.field' do
assert_select 'input#survey_submitted_flag_id'
end
assert_select 'div.field' do
assert_select 'input.btn.btn-primary[type=submit]'
end
end
end
end

test 'solved challenge survey shows for standard challenge when submitted flag is accepted' do
create(:standard_solved_challenge, challenge: @standard_challenge, team: @team1)
sign_in @team1.team_captain
get game_challenge_path(@standard_challenge)
assert_response :success
if @flag_found
assert_select 'form.well.form-inline' do
assert_select 'h3', I18n.t('surveys.new.header')
assert_select 'div.field', {:count => 3} do
assert_select 'label'
assert_select 'span.star-cb-group'
end
assert_select 'div.field' do
assert_select 'label'
assert_select 'textarea#survey_comment'
end
assert_select 'div.field' do
assert_select 'input#survey_submitted_flag_id'
end
assert_select 'div.field' do
assert_select 'input.btn.btn-primary[type=submit]'
end
end
end
end

test 'solved challenge survey shows for share challenge when submitted flag is accepted' do
share_chal = create(:share_challenge)
create(:standard_solved_challenge, challenge: share_chal, team: @team1)
sign_in @team1.team_captain
get game_challenge_path(share_chal)
assert_response :success
if @flag_found
assert_select 'form.well.form-inline' do
assert_select 'h3', I18n.t('surveys.new.header')
assert_select 'div.field', {:count => 3} do
assert_select 'label'
assert_select 'span.star-cb-group'
end
assert_select 'div.field' do
assert_select 'label'
assert_select 'textarea#survey_comment'
end
assert_select 'div.field' do
assert_select 'input#survey_submitted_flag_id'
end
assert_select 'div.field' do
assert_select 'input.btn.btn-primary[type=submit]'
end
end
end
end
end
7 changes: 7 additions & 0 deletions test/models/survey_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'test_helper'

class SurveyTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
Loading