From 97ee36f29061ddc47bfd2d08296717f04db03264 Mon Sep 17 00:00:00 2001 From: Artur-Gaifutdinov Date: Fri, 21 Feb 2014 23:38:45 -0500 Subject: [PATCH 1/3] Captcha --- Gemfile | 1 + Gemfile.lock | 11 ++++-- app/assets/stylesheets/questions.css.scss | 34 +++++++++++++++++++ app/controllers/answers_controller.rb | 14 +++++--- app/controllers/application_controller.rb | 2 ++ app/views/answers/_form_content.html.haml | 3 +- app/views/simple_captcha/_simple_captcha.haml | 5 +++ config/application.rb | 1 + config/locales/simple_captcha.en.yml | 7 ++++ 9 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 app/views/simple_captcha/_simple_captcha.haml create mode 100644 config/locales/simple_captcha.en.yml diff --git a/Gemfile b/Gemfile index 4bf72113..de1e6922 100644 --- a/Gemfile +++ b/Gemfile @@ -27,6 +27,7 @@ gem "semantic_menu", git: "git://github.com/michaek/semantic_menu.git" gem 'will_paginate' # Pagination gem 'redcarpet', '~> 3.0' # Markdown +gem 'simple_captcha', :git => 'git://github.com/ArturG/simple-captcha.git' # Gems used only for assets and not required # in production environments by default. diff --git a/Gemfile.lock b/Gemfile.lock index 3d8a7b9f..d56dcc8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,9 @@ +GIT + remote: git://github.com/ArturG/simple-captcha.git + revision: 707e56a96c7f44af7f4da77099ab1c53d2860044 + specs: + simple_captcha (0.1.6) + GIT remote: git://github.com/michaek/semantic_menu.git revision: 5298f586467cc9a91e85befcca673b8406c8846f @@ -126,7 +132,7 @@ GEM mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) - metaclass (0.0.3) + metaclass (0.0.4) metadown (1.0.1) redcarpet method_source (0.8.2) @@ -190,7 +196,7 @@ GEM rspec-core (2.14.7) rspec-expectations (2.14.5) diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.14.5) + rspec-mocks (2.14.6) rspec-rails (2.14.1) actionpack (>= 3.0) activemodel (>= 3.0) @@ -269,6 +275,7 @@ DEPENDENCIES rspec-rails sass-rails semantic_menu! + simple_captcha! simple_form! simplecov sqlite3 diff --git a/app/assets/stylesheets/questions.css.scss b/app/assets/stylesheets/questions.css.scss index 67a61796..a045961f 100644 --- a/app/assets/stylesheets/questions.css.scss +++ b/app/assets/stylesheets/questions.css.scss @@ -112,3 +112,37 @@ float:right; padding-top:4px; } + +.simple_captcha { + border: 1px solid #ccc; padding: 5px !important; +} + +.simple_captcha, .simple_captcha div { + margin-left: 150px; + display: table; +} + +.simple_captcha .simple_captcha_field, .simple_captcha .simple_captcha_image { + border: 1px solid #ccc; + margin: 0px 0px 2px 0px !important; + padding: 0px !important; +} + +.simple_captcha .simple_captcha_image img { + margin: 0px !important; + padding: 0px !important; + width: 110px !important; +} + +.simple_captcha .simple_captcha_label { + font-size: 12px; +} + +.simple_captcha .simple_captcha_field input { + width: 150px !important; + font-size: 16px; + border: none; + background-color: #efefef; +} + + diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index e9377081..996e1371 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -7,10 +7,16 @@ def create @answer = Answer.create params[:answer] @answer.question = @question @answer.user = current_user - - Notification.new_answer(@question).deliver - - create!(:notice => "Answer Posted!"){ question_url(params[:question_id]) } + + captcha = params[:answer][:captcha] + captcha_key = params[:answer][:captcha_key] + + if simple_captcha_valid?(captcha, captcha_key) + Notification.new_answer(@question).deliver + create!(:notice => "Answer Posted!"){ question_url(params[:question_id]) } + else + redirect_to @question, notice: "Incorrect captcha, are you robot?" + end end def update diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 95596f7c..0061be7f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,4 +1,6 @@ class ApplicationController < ActionController::Base + include SimpleCaptcha::ControllerHelpers + protect_from_forgery helper_method :title diff --git a/app/views/answers/_form_content.html.haml b/app/views/answers/_form_content.html.haml index 9974bd1e..8917c0fd 100644 --- a/app/views/answers/_form_content.html.haml +++ b/app/views/answers/_form_content.html.haml @@ -3,7 +3,8 @@ .inputs = f.input :description, :as => :text, :label => "Answer", :hint => "You can format your input with Markdown".html_safe - +.inputs + = f.show_simple_captcha .actions = f.button :submit, :value => "Post Answer", :class => "primary btn" diff --git a/app/views/simple_captcha/_simple_captcha.haml b/app/views/simple_captcha/_simple_captcha.haml new file mode 100644 index 00000000..9e572ce5 --- /dev/null +++ b/app/views/simple_captcha/_simple_captcha.haml @@ -0,0 +1,5 @@ +.simple_captcha + .simple_captcha_image + = simple_captcha_options[:image] + .simple_captcha_field + = simple_captcha_options[:field] \ No newline at end of file diff --git a/config/application.rb b/config/application.rb index d2382e0a..b3e0cbef 100644 --- a/config/application.rb +++ b/config/application.rb @@ -7,6 +7,7 @@ #Bundler.require *Rails.groups(:assets => %w(development test)) # If you want your assets lazily compiled in production, use this line Bundler.require(:default, :assets, Rails.env) + SimpleCaptcha.store = 'mongomapper' end module HacketyHackCom diff --git a/config/locales/simple_captcha.en.yml b/config/locales/simple_captcha.en.yml new file mode 100644 index 00000000..ac1d2bb0 --- /dev/null +++ b/config/locales/simple_captcha.en.yml @@ -0,0 +1,7 @@ +en: + simple_captcha: + placeholder: "Enter the value" + label: "Enter the code in the box:" + message: + default: "Secret Code did not match with the Image" + user: "The secret Image and code were different" \ No newline at end of file From 2e100fde5aa4093daf2935cc243610c187a08058 Mon Sep 17 00:00:00 2001 From: Artur-Gaifutdinov Date: Tue, 25 Feb 2014 14:37:48 -0500 Subject: [PATCH 2/3] Captcha cucumber tests --- app/controllers/answers_controller.rb | 2 +- features/answers.feature | 6 ++++-- features/step_definitions/answer_steps.rb | 5 +++++ spec/controllers/answers_controller_spec.rb | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 spec/controllers/answers_controller_spec.rb diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index 996e1371..b849a6fa 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -7,7 +7,7 @@ def create @answer = Answer.create params[:answer] @answer.question = @question @answer.user = current_user - + captcha = params[:answer][:captcha] captcha_key = params[:answer][:captcha_key] diff --git a/features/answers.feature b/features/answers.feature index 600859ff..a0fd2eee 100644 --- a/features/answers.feature +++ b/features/answers.feature @@ -5,7 +5,8 @@ Feature: CRUD actions for answers Scenario: Create an answer Given a question exists And I answer that question - Then I should be notified that my answer was submitted + Then I should see captcha + And I should be notified that my answer was submitted And an email should be sent to the author And I should be able to see my answer And my answer should show on my profile page @@ -14,5 +15,6 @@ Feature: CRUD actions for answers Given a question exists And I answer that question When I edit that answer - Then I should see the updated answer + Then I should see captcha + And I should see the updated answer diff --git a/features/step_definitions/answer_steps.rb b/features/step_definitions/answer_steps.rb index 515e2099..e037185f 100644 --- a/features/step_definitions/answer_steps.rb +++ b/features/step_definitions/answer_steps.rb @@ -40,3 +40,8 @@ page.should have_content('Edit: Did you try magic?') end +Then(/^I should see captcha$/) do + page.should have_css('.simple_captcha') + page.should have_css('.simple_captcha_image') + page.should have_css('.simple_captcha_field') +end \ No newline at end of file diff --git a/spec/controllers/answers_controller_spec.rb b/spec/controllers/answers_controller_spec.rb new file mode 100644 index 00000000..7b851a13 --- /dev/null +++ b/spec/controllers/answers_controller_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe AnswersController do + let(:newbie){Fabricate(:user)} + let(:tricky){Fabricate(:question)} + let(:genius){Fabricate(:answer)} + + describe "#create" do + context "captcha" do + it "responds with success" do + sign_in newbie + post :create, :question_id => tricky, :answer => genius + puts params + response.should be_success + end + end + end +end \ No newline at end of file From dc482f2c07502200f91cd50118c0c3c4e7f576dc Mon Sep 17 00:00:00 2001 From: Artur-Gaifutdinov Date: Tue, 25 Feb 2014 21:42:25 -0500 Subject: [PATCH 3/3] Captcha RSpec tests --- Gemfile.lock | 6 ++++-- app/controllers/answers_controller.rb | 4 +--- app/models/answer.rb | 1 - spec/controllers/answers_controller_spec.rb | 22 ++++++++++++++------ spec/fabricators/answer_fabricator.rb | 2 +- spec/views/questions/index.html.haml_spec.rb | 2 +- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d56dcc8e..93e5c7c3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,7 +50,9 @@ GEM multi_json (~> 1.0) addressable (2.3.5) arel (3.0.3) - bcrypt-ruby (3.1.2) + bcrypt (3.1.7) + bcrypt-ruby (3.1.5) + bcrypt (>= 3.1.3) bson (1.9.2) bson_ext (1.9.2) bson (~> 1.9.2) @@ -221,7 +223,7 @@ GEM multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.8) + sqlite3 (1.3.9) term-ansicolor (1.3.0) tins (~> 1.0) thor (0.18.1) diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index b849a6fa..ed84dbdf 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -11,7 +11,7 @@ def create captcha = params[:answer][:captcha] captcha_key = params[:answer][:captcha_key] - if simple_captcha_valid?(captcha, captcha_key) + if simple_captcha_valid?(captcha, captcha_key) && !captcha_key.nil? && !captcha_key.nil? Notification.new_answer(@question).deliver create!(:notice => "Answer Posted!"){ question_url(params[:question_id]) } else @@ -25,7 +25,5 @@ def update format.html { redirect_to question_url(resource.question) } end end - - end diff --git a/app/models/answer.rb b/app/models/answer.rb index bfed4f8a..71c3df7f 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -8,5 +8,4 @@ class Answer belongs_to :question belongs_to :user - end diff --git a/spec/controllers/answers_controller_spec.rb b/spec/controllers/answers_controller_spec.rb index 7b851a13..4e75f390 100644 --- a/spec/controllers/answers_controller_spec.rb +++ b/spec/controllers/answers_controller_spec.rb @@ -3,15 +3,25 @@ describe AnswersController do let(:newbie){Fabricate(:user)} let(:tricky){Fabricate(:question)} - let(:genius){Fabricate(:answer)} describe "#create" do - context "captcha" do - it "responds with success" do + + before(:each) do + sign_in newbie + @valid_captcha_answer = { :description => "Foo", :captcha => "Bar", :captcha_key => "FooBar" } + @invalid_captcha_answer = { :description => "Foo"} + end + + context "post answer" do + it "responds with success if captcha is correct" do sign_in newbie - post :create, :question_id => tricky, :answer => genius - puts params - response.should be_success + post :create, :question_id => tricky, :answer => @valid_captcha_answer + flash[:notice].should == "Answer Posted!" + end + + it "responds with failure if captcha is incorrect" do + post :create, :question_id => tricky, :answer => @invalid_captcha_answer + flash[:notice].should == "Incorrect captcha, are you robot?" end end end diff --git a/spec/fabricators/answer_fabricator.rb b/spec/fabricators/answer_fabricator.rb index a02e7ab2..e5304cc8 100644 --- a/spec/fabricators/answer_fabricator.rb +++ b/spec/fabricators/answer_fabricator.rb @@ -1,4 +1,4 @@ Fabricator(:answer) do description "MyString" - user "" + question_id question end \ No newline at end of file diff --git a/spec/views/questions/index.html.haml_spec.rb b/spec/views/questions/index.html.haml_spec.rb index f371781c..0e219f1d 100644 --- a/spec/views/questions/index.html.haml_spec.rb +++ b/spec/views/questions/index.html.haml_spec.rb @@ -12,7 +12,7 @@ end it "renders an autodiscovery link in for the head content" do - render :template => "questions/index.html.haml", :locals => {:collection => [question]} + render :template => "questions/index", :handlers => [:haml], :locals => {:collection => [question]} view.content_for(:head).should include(questions_url(format: :atom)) end