Commit db134de31549961bf8f1deeeaa26ca813357bad9
1 parent
7684f638
Exists in
theme-brasil-digital-from-staging
and in
5 other branches
Implemented votes with captcha
Showing
6 changed files
with
74 additions
and
34 deletions
Show diff stats
lib/noosfero/api/captcha_session_store.rb
| ... | ... | @@ -1,30 +0,0 @@ |
| 1 | -class Noosfero::API::CaptchaSessionStore | |
| 2 | - | |
| 3 | - attr_accessor :data | |
| 4 | - attr_reader :private_token | |
| 5 | - | |
| 6 | - def self.create | |
| 7 | - key = SecureRandom.hex | |
| 8 | - store = Noosfero::API::CaptchaSessionStore.new(key) | |
| 9 | - Rails.cache.write(store.private_token, store, expires_in: 300) | |
| 10 | - return store | |
| 11 | - end | |
| 12 | - | |
| 13 | - def initialize(key) | |
| 14 | - @private_token = key | |
| 15 | - end | |
| 16 | - | |
| 17 | - def self.get(key) | |
| 18 | - Rails.cache.fetch(key) | |
| 19 | - end | |
| 20 | - | |
| 21 | - def store | |
| 22 | - Rails.cache.write(@private_token, self) | |
| 23 | - end | |
| 24 | - | |
| 25 | - def destroy | |
| 26 | - Rails.cache.delete(@private_token) | |
| 27 | - end | |
| 28 | - | |
| 29 | - | |
| 30 | -end |
lib/noosfero/api/helpers.rb
| ... | ... | @@ -23,7 +23,8 @@ require 'grape' |
| 23 | 23 | |
| 24 | 24 | def current_tmp_user |
| 25 | 25 | private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s |
| 26 | - @current_tmp_user = Noosfero::API::CaptchaSessionStore.get(private_token) | |
| 26 | + ## Get the "captcha" session store | |
| 27 | + @current_tmp_user = Noosfero::API::SessionStore.get("captcha##{private_token}") | |
| 27 | 28 | @current_tmp_user |
| 28 | 29 | end |
| 29 | 30 | ... | ... |
lib/noosfero/api/session.rb
| ... | ... | @@ -16,7 +16,11 @@ module Noosfero |
| 16 | 16 | # this return is just to improve the clarity of the execution path |
| 17 | 17 | return unless test_captcha(remote_ip, params, environment) |
| 18 | 18 | ## Creates and caches a captcha session store |
| 19 | - store = Noosfero::API::CaptchaSessionStore.create | |
| 19 | + store = Noosfero::API::SessionStore.create("captcha") | |
| 20 | + ## Initialize the data for the session store | |
| 21 | + store.data = [] | |
| 22 | + ## Put it back in cache | |
| 23 | + store.store | |
| 20 | 24 | { "private_token" => "#{store.private_token}" } |
| 21 | 25 | end |
| 22 | 26 | ... | ... |
lib/noosfero/api/v1/articles.rb
| ... | ... | @@ -139,8 +139,21 @@ module Noosfero |
| 139 | 139 | # FIXME verify allowed values |
| 140 | 140 | render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value) |
| 141 | 141 | article = find_article(environment.articles, params[:id]) |
| 142 | - vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | |
| 143 | - {:vote => vote.save} | |
| 142 | + ## If login with captcha | |
| 143 | + if @current_tmp_user | |
| 144 | + vote = (@current_tmp_user.data.include? article.id) ? false : true | |
| 145 | + if vote | |
| 146 | + @current_tmp_user.data << article.id | |
| 147 | + @current_tmp_user.store | |
| 148 | + vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | |
| 149 | + {:vote => vote.save} | |
| 150 | + else | |
| 151 | + {:vote => false} | |
| 152 | + end | |
| 153 | + else | |
| 154 | + vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | |
| 155 | + {:vote => vote.save} | |
| 156 | + end | |
| 144 | 157 | end |
| 145 | 158 | |
| 146 | 159 | desc 'Return the children of a article identified by id' do | ... | ... |
test/unit/api/articles_test.rb
| ... | ... | @@ -127,6 +127,37 @@ class ArticlesTest < ActiveSupport::TestCase |
| 127 | 127 | assert_equal 1, json['total_followers'] |
| 128 | 128 | end |
| 129 | 129 | |
| 130 | + should 'not perform a vote twice in same article' do | |
| 131 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
| 132 | + @params[:value] = 1 | |
| 133 | + ## Perform a vote twice in API should compute only one vote | |
| 134 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
| 135 | + json = JSON.parse(last_response.body) | |
| 136 | + | |
| 137 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
| 138 | + json = JSON.parse(last_response.body) | |
| 139 | + | |
| 140 | + total = article.votes_total | |
| 141 | + | |
| 142 | + assert_equal 1, total | |
| 143 | + end | |
| 144 | + | |
| 145 | + should 'not perform a vote in favor and against a proposal' do | |
| 146 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
| 147 | + @params[:value] = 1 | |
| 148 | + ## Perform a vote in favor a proposal | |
| 149 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
| 150 | + json = JSON.parse(last_response.body) | |
| 151 | + assert_equal 201, last_response.status | |
| 152 | + ## Perform a vote against a proposal | |
| 153 | + @params[:value] = -1 | |
| 154 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
| 155 | + json = JSON.parse(last_response.body) | |
| 156 | + ## The api should not allow to save this vote | |
| 157 | + assert_equal false, json['vote'] | |
| 158 | + end | |
| 159 | + | |
| 160 | + | |
| 130 | 161 | should 'perform a vote in a article identified by id' do |
| 131 | 162 | article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") |
| 132 | 163 | @params[:value] = 1 |
| ... | ... | @@ -136,6 +167,7 @@ class ArticlesTest < ActiveSupport::TestCase |
| 136 | 167 | |
| 137 | 168 | assert_not_equal 401, last_response.status |
| 138 | 169 | assert_equal true, json['vote'] |
| 170 | + | |
| 139 | 171 | end |
| 140 | 172 | |
| 141 | 173 | expose_attributes = %w(id body abstract created_at title author profile categories image votes_for votes_against setting position hits start_date end_date tag_list parent children children_count) | ... | ... |
test/unit/api/login_captcha_test.rb
| ... | ... | @@ -47,6 +47,26 @@ class LoginCaptchaTest < ActiveSupport::TestCase |
| 47 | 47 | assert_equal true, json['vote'] |
| 48 | 48 | end |
| 49 | 49 | |
| 50 | + should 'not perform a vote twice in same article' do | |
| 51 | + login_with_captcha | |
| 52 | + article = create_article('Article 1') | |
| 53 | + params[:value] = 1 | |
| 54 | + | |
| 55 | + ## Perform a vote twice in API should compute only one vote | |
| 56 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
| 57 | + json = JSON.parse(last_response.body) | |
| 58 | + assert_equal true, json['vote'] | |
| 59 | + | |
| 60 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
| 61 | + json = JSON.parse(last_response.body) | |
| 62 | + ## Should not allow vote again | |
| 63 | + assert_equal false, json['vote'] | |
| 64 | + | |
| 65 | + total = article.votes_total | |
| 66 | + | |
| 67 | + assert_equal 1, total | |
| 68 | + end | |
| 69 | + | |
| 50 | 70 | should 'not follow any article' do |
| 51 | 71 | login_with_captcha |
| 52 | 72 | article = create_article('Article 1') | ... | ... |