refinerycms-polls 0.0.2.dev → 0.0.4.dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +23 -0
- data/Gemfile +3 -2
- data/README.md +7 -3
- data/Rakefile +2 -0
- data/app/assets/javascripts/refinery/polls/poll.js +2 -0
- data/app/assets/javascripts/refinery/polls/poll_form.js.coffee +6 -0
- data/app/assets/stylesheets/refinery/polls/polls.css.scss +7 -0
- data/app/controllers/refinery/polls/admin/answers_controller.rb +16 -3
- data/app/controllers/refinery/polls/questions_controller.rb +19 -16
- data/app/models/refinery/polls/answer.rb +15 -1
- data/app/models/refinery/polls/question.rb +22 -15
- data/app/models/refinery/polls/vote.rb +5 -3
- data/app/views/refinery/polls/questions/_answers_form.html.erb +4 -1
- data/app/views/refinery/polls/questions/_poll.html.erb +1 -1
- data/app/views/refinery/polls/questions/index.html.erb +4 -3
- data/app/views/refinery/polls/questions/show.html.erb +10 -19
- data/config/locales/en.yml +19 -19
- data/lib/generators/refinery/polls_generator.rb +5 -1
- data/lib/generators/refinery/templates/app/assets/stylesheets/refinery/polls/poll.css.scss +28 -0
- data/lib/refinery/polls/configuration.rb +1 -0
- data/lib/refinery/polls/engine.rb +1 -1
- data/lib/refinery/polls/version.rb +1 -1
- data/spec/models/refinery/polls/answer_spec.rb +17 -0
- data/spec/models/refinery/polls/question_spec.rb +31 -1
- data/spec/models/refinery/polls/vote_spec.rb +35 -0
- data/spec/requests/refinery/polls/admin/answers_spec.rb +114 -0
- data/spec/requests/refinery/polls/admin/questions_spec.rb +1 -1
- data/spec/requests/refinery/polls/questions_spec.rb +138 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/factories/refinery/polls.rb +12 -2
- metadata +17 -2
- data/app/assets/javascripts/refinery/polls/poll_form.js +0 -8
data/CHANGELOG.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
## v0.0.1.dev
|
2
|
+
|
3
|
+
* Create polls in refinerycms admin.
|
4
|
+
* Add Answers to poll.
|
5
|
+
* Render polls in refinerycms.
|
6
|
+
|
7
|
+
## v0.0.2.dev
|
8
|
+
|
9
|
+
* Config vote interval in config/refinery/poll initializer.
|
10
|
+
|
11
|
+
## v0.0.3.dev
|
12
|
+
|
13
|
+
* Add css file app/assets/stylesheets/refinery/polls/poll.css.scss to override poll styles.
|
14
|
+
|
15
|
+
## v0.0.4.dev
|
16
|
+
* Poll checkbox as labels to better user experience.
|
17
|
+
* Translate js to coffee script.
|
18
|
+
* Fix jquery library loads from extension and not from cms.
|
19
|
+
* Fix poll form double submit if user does dobel click.
|
20
|
+
* Fix howto finds votes for question with already_voted?(remote_ip) in Question model.
|
21
|
+
* Fix tests for all models/controllers
|
22
|
+
* Add tests for question controller
|
23
|
+
* Add documentation
|
data/Gemfile
CHANGED
@@ -2,9 +2,9 @@ source "http://rubygems.org"
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
gem 'refinerycms', '~> 2.0.0', :git => 'git://github.com/resolve/refinerycms.git'
|
5
|
+
gem 'refinerycms', '~> 2.0.0', :git => 'git://github.com/resolve/refinerycms.git', :branch => '2-0-stable'
|
6
6
|
gem 'refinerycms-i18n', :git => 'git://github.com/parndt/refinerycms-i18n.git'
|
7
|
-
gem 'refinerycms-settings', :git => 'git://github.com/parndt/refinerycms-settings.git'
|
7
|
+
gem 'refinerycms-settings', :git => 'git://github.com/parndt/refinerycms-settings.git', :branch => '2-0-stable'
|
8
8
|
|
9
9
|
# Refinery/rails should pull in the proper versions of these
|
10
10
|
group :assets do
|
@@ -19,6 +19,7 @@ group :development, :test do
|
|
19
19
|
gem 'refinerycms-testing', '~> 2.0.0'
|
20
20
|
gem 'factory_girl_rails'
|
21
21
|
gem 'generator_spec'
|
22
|
+
gem 'activesupport'
|
22
23
|
|
23
24
|
require 'rbconfig'
|
24
25
|
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Include the latest [gem](http://rubygems.org/gems/refinerycms-polls) into your Refinery CMS application's Gemfile:
|
6
6
|
|
7
|
-
gem 'refinerycms-polls', '~> 0.0.
|
7
|
+
gem 'refinerycms-polls', '~> 0.0.4.dev'
|
8
8
|
|
9
9
|
Then type the following at command line inside your Refinery CMS application's root directory:
|
10
10
|
|
@@ -60,11 +60,15 @@ In summary you can:
|
|
60
60
|
* Set when starts and ends your polls.
|
61
61
|
* Show results for your polls.
|
62
62
|
* Set votes for anonymous users by IP addres
|
63
|
-
* Set
|
63
|
+
* Set duration period to vote. (if a guest vote it will need to wait X time to vote again)
|
64
64
|
|
65
65
|
## Todo
|
66
66
|
|
67
67
|
* Vote tracking by cookies.
|
68
68
|
* Documentation
|
69
69
|
* Tests
|
70
|
-
* Wiki
|
70
|
+
* Wiki
|
71
|
+
|
72
|
+
|
73
|
+
## License
|
74
|
+
RefineryCMS Polls extension is released under the MIT license and is copyright (c) 2012 Agustin Viñao
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ module Refinery
|
|
5
5
|
|
6
6
|
crudify :'refinery/polls/answer', :title_attribute => 'title', :xhr_paging => true
|
7
7
|
before_filter :find_question
|
8
|
-
before_filter :find_answer, :only => [:edit, :update]
|
8
|
+
before_filter :find_answer, :only => [:edit, :update, :destroy]
|
9
9
|
|
10
10
|
def index
|
11
11
|
paginate_all_answers
|
@@ -16,18 +16,19 @@ module Refinery
|
|
16
16
|
|
17
17
|
def create
|
18
18
|
if (@answer = ::Refinery::Polls::Answer.create({:question_id => @question.id}.merge(params[:answer]))).valid?
|
19
|
-
flash.now[:notice] = "#{@answer.title} was successfully
|
19
|
+
flash.now[:notice] = "'#{@answer.title}' was successfully added."
|
20
20
|
self.index
|
21
21
|
@dialog_successful = true
|
22
22
|
render :index
|
23
23
|
else
|
24
|
+
flash.now[:notice] = "There were problems"
|
24
25
|
render :action => 'new'
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
def update
|
29
30
|
if @answer.update_attributes({:question_id => @question.id}.merge(params[:answer]))
|
30
|
-
flash.now[:notice] = "#{@answer.title} was successfully updated."
|
31
|
+
flash.now[:notice] = "'#{@answer.title}' was successfully updated."
|
31
32
|
self.index
|
32
33
|
@dialog_successful = true
|
33
34
|
render :index
|
@@ -36,6 +37,18 @@ module Refinery
|
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
40
|
+
def destroy
|
41
|
+
answer_title = @answer.title
|
42
|
+
if @answer.destroy
|
43
|
+
flash.now[:notice] = "'#{answer_title}' was successfully removed."
|
44
|
+
@dialog_successful = true
|
45
|
+
else
|
46
|
+
flash.now[:notice] = "There were problems"
|
47
|
+
end
|
48
|
+
self.index
|
49
|
+
render :index
|
50
|
+
end
|
51
|
+
|
39
52
|
private
|
40
53
|
def find_answer
|
41
54
|
@answer = ::Refinery::Polls::Answer.find_by_slug_or_id(params[:id])
|
@@ -2,11 +2,11 @@ module Refinery
|
|
2
2
|
module Polls
|
3
3
|
class QuestionsController < ::ApplicationController
|
4
4
|
|
5
|
-
before_filter :find_all_questions, :only => [:index]
|
5
|
+
before_filter :find_all_questions, :only => [:index, :show]
|
6
6
|
before_filter :find_page, :except => [:submit]
|
7
|
-
before_filter :find_vote, :only => [:show, :create]
|
8
|
-
before_filter :find_answer, :only => [:submit]
|
9
7
|
before_filter :find_question, :only => [:submit, :show]
|
8
|
+
before_filter :find_answer, :only => [:submit]
|
9
|
+
before_filter :find_vote, :only => [:show, :create, :submit]
|
10
10
|
respond_to :html, :js, :json
|
11
11
|
def index
|
12
12
|
# you can use meta fields from your model instead (e.g. browser_title)
|
@@ -20,21 +20,24 @@ module Refinery
|
|
20
20
|
present(@page)
|
21
21
|
end
|
22
22
|
|
23
|
+
|
24
|
+
# Handle votes from questions
|
25
|
+
#
|
26
|
+
# @param [id] Id of question voted
|
27
|
+
# @param [question_id] Value of the answer selected by guest
|
28
|
+
# @return [String] Question results
|
23
29
|
def submit
|
24
|
-
@vote
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@answer.votes_count += 1
|
30
|
-
@answer.save
|
31
|
-
@vote = ::Refinery::Polls::Vote.vote_by_ip(@question, @answer, request.remote_ip)
|
32
|
-
end
|
33
|
-
respond_to do |format|
|
34
|
-
format.js
|
35
|
-
format.html
|
30
|
+
if @vote.nil?
|
31
|
+
if @answer.nil?
|
32
|
+
flash[:notice] = t(".no_answer_selected")
|
33
|
+
else
|
34
|
+
@vote = ::Refinery::Polls::Vote.vote_by_ip(@answer, request.remote_ip)
|
36
35
|
end
|
37
36
|
end
|
37
|
+
respond_to do |format|
|
38
|
+
format.js
|
39
|
+
format.html
|
40
|
+
end
|
38
41
|
end
|
39
42
|
|
40
43
|
protected
|
@@ -55,7 +58,7 @@ module Refinery
|
|
55
58
|
end
|
56
59
|
|
57
60
|
def find_vote
|
58
|
-
@vote = ::Refinery::Polls::Vote.
|
61
|
+
@vote = ::Refinery::Polls::Vote.get_vote(@question, request.remote_ip)
|
59
62
|
end
|
60
63
|
end
|
61
64
|
end
|
@@ -8,7 +8,7 @@ module Refinery
|
|
8
8
|
|
9
9
|
acts_as_indexed :fields => [:title]
|
10
10
|
|
11
|
-
validates :title, :presence => true, :uniqueness =>
|
11
|
+
validates :title, :presence => true, :uniqueness => { :scope => :question_id}
|
12
12
|
|
13
13
|
attr_accessible :title, :question_id, :position
|
14
14
|
attr_accessor :locale
|
@@ -22,6 +22,20 @@ module Refinery
|
|
22
22
|
attr_accessible :locale
|
23
23
|
end
|
24
24
|
|
25
|
+
# Get a string to represent a dom id
|
26
|
+
#
|
27
|
+
# @return [String] Returns the dom id representation for the current object
|
28
|
+
def dom_id
|
29
|
+
"answer_#{id}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get an array of title and votes_count
|
33
|
+
#
|
34
|
+
# @return [Array] Returns an array of title and votes_count
|
35
|
+
def data_result
|
36
|
+
[title, votes_count]
|
37
|
+
end
|
38
|
+
|
25
39
|
def self.translated
|
26
40
|
with_translations(::Globalize.locale)
|
27
41
|
end
|
@@ -26,17 +26,33 @@ module Refinery
|
|
26
26
|
|
27
27
|
has_many :answers, :class_name => '::Refinery::Polls::Answer'
|
28
28
|
|
29
|
+
# Get all actives questions by start_date and end_date
|
30
|
+
#
|
31
|
+
# @return [Array] Array of Refinery::Polls::Question
|
29
32
|
def self.actives
|
30
33
|
where("start_date <= ? and end_date >= ?", Date.today, Date.today)
|
31
34
|
end
|
32
35
|
|
36
|
+
# Check if we have a vote by ip address
|
37
|
+
#
|
38
|
+
# @param [String] A string to represent an IP address
|
39
|
+
# @return [::Refinery::Polls::Vote, nil] Returns the vote finded or nil
|
40
|
+
def already_voted?(remote_ip)
|
41
|
+
answers.joins(:votes).where(Refinery::Polls::Vote.table_name.to_sym => {:created_at => Time.now.utc - Refinery::Polls.vote_duration, :ip => remote_ip}).first
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get al data for answers and total votes count
|
45
|
+
#
|
46
|
+
# @return [Array] Returns an array with [[title,votes_count]..[title,votes_count]], total_votes]
|
33
47
|
def answers_with_data
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
48
|
+
return answers.map(&:data_result), total_votes
|
49
|
+
end
|
50
|
+
|
51
|
+
# Calculate the total votes for current question
|
52
|
+
#
|
53
|
+
# @return [Integer] Returns the value of total votes
|
54
|
+
def total_votes
|
55
|
+
answers.sum(&:votes_count)
|
40
56
|
end
|
41
57
|
|
42
58
|
class << self
|
@@ -48,15 +64,6 @@ module Refinery
|
|
48
64
|
end
|
49
65
|
end
|
50
66
|
end
|
51
|
-
# def self.active_poll(user_id)
|
52
|
-
# users_polls = UsersPoll.find_all_by_user_id(user_id, :select => :poll_id)
|
53
|
-
# polls = users_polls.count > 0 ? Poll.active.find(:all, :conditions => ["id NOT IN (?)", users_polls.collect {|up| up.poll_id } ]) : Poll.active
|
54
|
-
# polls.count > 0 ? polls.first : nil
|
55
|
-
# end
|
56
|
-
|
57
|
-
|
58
|
-
# acceso a variables connfiguradas
|
59
|
-
#self.per_page = Refinery::Blog.posts_per_page
|
60
67
|
end
|
61
68
|
end
|
62
69
|
end
|
@@ -5,20 +5,22 @@ module Refinery
|
|
5
5
|
acts_as_indexed :fields => [:question_id, :answer_id, :ip]
|
6
6
|
|
7
7
|
belongs_to :question, :class_name => '::Refinery::Polls::Question'
|
8
|
-
belongs_to :answer, :class_name => '::Refinery::Polls::Answer'
|
8
|
+
belongs_to :answer, :class_name => '::Refinery::Polls::Answer', :counter_cache => true
|
9
9
|
|
10
10
|
attr_accessible :question_id, :answer_id, :ip
|
11
11
|
|
12
12
|
# Create Vote for Question, Answer and IP
|
13
|
+
#
|
13
14
|
# @param [::Refinery::Polls::Question] Question object
|
14
15
|
# @parama [::Refinery::Polls::Answer] Answer object
|
15
16
|
# @return [::Refinery::Polls::Vote] Vote object created
|
16
17
|
|
17
|
-
def self.vote_by_ip(
|
18
|
-
self.create(:answer_id => answer.id, :question_id => question.id, :ip => ip)
|
18
|
+
def self.vote_by_ip(answer, ip)
|
19
|
+
self.create(:answer_id => answer.id, :question_id => answer.question.id, :ip => ip)
|
19
20
|
end
|
20
21
|
|
21
22
|
# Find vote for Question by IP
|
23
|
+
#
|
22
24
|
# @param [::Refinery::Polls::Question] Question object
|
23
25
|
# @parama [Request] Request object to use remote_ip
|
24
26
|
# @return [::Refinery::Polls::Vote] Vote object created
|
@@ -4,7 +4,10 @@
|
|
4
4
|
:remote => true,
|
5
5
|
:html => {:id => "reinerycms-poll-#{question.slug}"} do |f| %>
|
6
6
|
<% question.answers.each do |answer| %>
|
7
|
-
|
7
|
+
<%= content_tag_for :li, answer do %>
|
8
|
+
<%= radio_button_tag("answer_id", answer.id, false, id: answer.dom_id) %>
|
9
|
+
<%= label_tag answer.dom_id, answer.title %>
|
10
|
+
<% end %>
|
8
11
|
<% end %>
|
9
12
|
<% end %>
|
10
13
|
</ul>
|
@@ -6,5 +6,5 @@
|
|
6
6
|
<%= (vote = ::Refinery::Polls::Vote.get_vote(question, request.remote_ip)).nil? ? render(:partial => 'refinery/polls/questions/answers_form', :locals => {:question => question}) : render(:partial => 'refinery/polls/questions/results', :locals => {:question => question, :vote => vote}) %>
|
7
7
|
<% end %>
|
8
8
|
</div>
|
9
|
-
<% content_for :javascripts, javascript_include_tag('
|
9
|
+
<% content_for :javascripts, javascript_include_tag('refinery/polls/poll', 'refinery/polls/poll_form') %>
|
10
10
|
<% end %>
|
@@ -1,9 +1,10 @@
|
|
1
1
|
<% content_for :body_content_left do %>
|
2
|
+
<h4>Polls</h4>
|
2
3
|
<ul id="questions">
|
3
|
-
<% @questions.each do |
|
4
|
-
|
4
|
+
<% @questions.each do |question| %>
|
5
|
+
<%= content_tag_for :li, question do %>
|
5
6
|
<%= link_to question.title, refinery.polls_question_path(question) %>
|
6
|
-
|
7
|
+
<% end %>
|
7
8
|
<% end %>
|
8
9
|
</ul>
|
9
10
|
<% end %>
|
@@ -1,33 +1,24 @@
|
|
1
|
+
<% content_for :stylesheets, stylesheet_link_tag('refinery/polls/polls') %>
|
1
2
|
<% content_for :body_content_title do %>
|
2
3
|
<%= @question.title %>
|
3
4
|
<% end %>
|
4
5
|
|
5
6
|
<% content_for :body_content_left do %>
|
6
|
-
<
|
7
|
-
<
|
8
|
-
|
9
|
-
<%=
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
<p>
|
15
|
-
<%=raw @question.start_date %>
|
16
|
-
</p>
|
17
|
-
</section>
|
18
|
-
<section>
|
19
|
-
<h1>End Date</h1>
|
20
|
-
<p>
|
21
|
-
<%=raw @question.end_date %>
|
22
|
-
</p>
|
23
|
-
</section>
|
7
|
+
<div class="refinery-polls">
|
8
|
+
<ul>
|
9
|
+
<li>Title: <%=raw @question.title %></li>
|
10
|
+
<li>Start: <%=l(@question.start_date, :format => :short) %></li>
|
11
|
+
<li>End: <%=l(@question.end_date, :format => :short) %></li>
|
12
|
+
<li>Votes: <%=pluralize(@question.total_votes, "vote") %></li>
|
13
|
+
<ul>
|
14
|
+
</div>
|
24
15
|
<% end %>
|
25
16
|
|
26
17
|
<% content_for :body_content_right do %>
|
27
18
|
<aside>
|
28
19
|
<h2><%= t('.other') %></h2>
|
29
20
|
<ul id="questions">
|
30
|
-
<% @questions.each do |
|
21
|
+
<% @questions.each do |question| %>
|
31
22
|
<li>
|
32
23
|
<%= link_to question.title, refinery.polls_question_path(question) %>
|
33
24
|
</li>
|
data/config/locales/en.yml
CHANGED
@@ -2,39 +2,39 @@ en:
|
|
2
2
|
refinery:
|
3
3
|
plugins:
|
4
4
|
polls:
|
5
|
-
title:
|
5
|
+
title: Questions
|
6
6
|
polls:
|
7
7
|
admin:
|
8
8
|
questions:
|
9
9
|
actions:
|
10
|
-
create_new: Add New
|
11
|
-
reorder: Reorder
|
12
|
-
reorder_done: Done Reordering
|
10
|
+
create_new: Add New Question
|
11
|
+
reorder: Reorder Questions
|
12
|
+
reorder_done: Done Reordering Questions
|
13
13
|
records:
|
14
|
-
title:
|
14
|
+
title: Questions
|
15
15
|
sorry_no_results: Sorry! There are no results found.
|
16
|
-
no_items_yet: There are no
|
16
|
+
no_items_yet: There are no Questions yet. Click "Add New Question" to add your first question.
|
17
17
|
question:
|
18
|
-
view_live_html: View this
|
19
|
-
edit: Edit this
|
20
|
-
delete: Remove this
|
21
|
-
manage_answers: View answers for this
|
18
|
+
view_live_html: View this question live <br/><em>(opens in a new window)</em>
|
19
|
+
edit: Edit this question
|
20
|
+
delete: Remove this question forever
|
21
|
+
manage_answers: View answers for this question
|
22
22
|
answers:
|
23
23
|
actions:
|
24
|
-
create_new: Add New
|
25
|
-
reorder: Reorder
|
26
|
-
reorder_done: Done Reordering
|
24
|
+
create_new: Add New Question Answer
|
25
|
+
reorder: Reorder Question Answers
|
26
|
+
reorder_done: Done Reordering Question Answers
|
27
27
|
records:
|
28
|
-
title:
|
28
|
+
title: Question Answers
|
29
29
|
sorry_no_results: Sorry! There are no results found.
|
30
|
-
no_items_yet: There are no
|
30
|
+
no_items_yet: There are no Question Answers yet. Click "Add New Question Answer" to add your first question answer.
|
31
31
|
answer:
|
32
|
-
view_live_html: View this
|
33
|
-
edit: Edit this
|
34
|
-
delete: Remove this
|
32
|
+
view_live_html: View this question answer live <br/><em>(opens in a new window)</em>
|
33
|
+
edit: Edit this question answer
|
34
|
+
delete: Remove this question answer forever
|
35
35
|
questions:
|
36
36
|
show:
|
37
|
-
other: Other
|
37
|
+
other: Other Questions
|
38
38
|
activerecord:
|
39
39
|
attributes:
|
40
40
|
'refinery/polls/question':
|
@@ -10,7 +10,11 @@ module Refinery
|
|
10
10
|
def generate_poll_initializer
|
11
11
|
template "config/initializers/refinery/poll.rb.erb", File.join(destination_root, "config", "initializers", "refinery", "poll.rb")
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
|
+
def generate_styles_to_assets
|
15
|
+
template "app/assets/stylesheets/refinery/polls/poll.css.scss", File.join(destination_root, "app", "assets", "stylesheets", "refinery", "polls", "poll.css.scss")
|
16
|
+
end
|
17
|
+
|
14
18
|
def append_load_seed_data
|
15
19
|
create_file 'db/seeds.rb' unless File.exists?(File.join(destination_root, 'db', 'seeds.rb'))
|
16
20
|
append_file 'db/seeds.rb', :verbose => true do
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/* These are all classes used by poll to render */
|
2
|
+
/*
|
3
|
+
.reinerycms-polls-form h3{
|
4
|
+
padding:5px;
|
5
|
+
}
|
6
|
+
.reinerycms-polls-form ul{
|
7
|
+
list-style-type: none;
|
8
|
+
padding: 10px;
|
9
|
+
margin: 0;
|
10
|
+
}
|
11
|
+
.reinerycms-polls-pollbar {
|
12
|
+
margin: 1px;
|
13
|
+
font-size: 13px;
|
14
|
+
line-height: 15px;
|
15
|
+
height: 15px;
|
16
|
+
background-image: image_url('refinery/polls/pollbg.gif');
|
17
|
+
border: 1px solid #ffffff;
|
18
|
+
}
|
19
|
+
.reinerycms-polls-pollbar IMG {
|
20
|
+
display: inline;
|
21
|
+
border: 0px;
|
22
|
+
padding: 0px;
|
23
|
+
margin: 0px;
|
24
|
+
}
|
25
|
+
.reinerycms-polls-results{
|
26
|
+
border:1px solid #CCC;
|
27
|
+
}
|
28
|
+
*/
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Refinery
|
4
|
+
module Polls
|
5
|
+
describe Answer do
|
6
|
+
describe "validations" do
|
7
|
+
subject do
|
8
|
+
FactoryGirl.create(:answer, :title => "Answer 1")
|
9
|
+
end
|
10
|
+
|
11
|
+
it { should be_valid }
|
12
|
+
its(:errors) { should be_empty }
|
13
|
+
its(:title) { should == "Answer 1" }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Refinery
|
4
4
|
module Polls
|
5
|
-
describe
|
5
|
+
describe Question do
|
6
6
|
describe "validations" do
|
7
7
|
subject do
|
8
8
|
FactoryGirl.create(:question,
|
@@ -13,6 +13,36 @@ module Refinery
|
|
13
13
|
its(:errors) { should be_empty }
|
14
14
|
its(:title) { should == "Refinery CMS" }
|
15
15
|
end
|
16
|
+
describe "class methods" do
|
17
|
+
before do
|
18
|
+
Factory.create(:question)
|
19
|
+
Factory.create(:question,
|
20
|
+
start_date: Time.now+2.days,
|
21
|
+
end_date: Time.now+10.days)
|
22
|
+
end
|
23
|
+
subject { Question.first }
|
24
|
+
it "should get one question active" do
|
25
|
+
Question.actives.should == [subject]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
describe "instance methods" do
|
29
|
+
before do
|
30
|
+
question = Factory.create(:question)
|
31
|
+
@times = 3
|
32
|
+
@answer = Factory.create(:answer, question: question)
|
33
|
+
(@times-1).times{ Factory.create(:answer, question: question) }
|
34
|
+
@ip = "192.168.1.1"
|
35
|
+
@vote = Factory.create(:vote, answer: @answer, ip: @ip)
|
36
|
+
end
|
37
|
+
subject{ Question.first }
|
38
|
+
it { subject.answers.size == @times }
|
39
|
+
it { subject.total_votes.should == subject.answers.sum(&:votes_count) }
|
40
|
+
it "should get answers data for view" do
|
41
|
+
subject.answers_with_data.should == [subject.answers.collect{|a| [a.title, a.votes_count]}, subject.total_votes]
|
42
|
+
end
|
43
|
+
it { subject.already_voted?("127.0.0.1").should be_false }
|
44
|
+
it { subject.already_voted?("192.168.1.1").should be_nil }
|
45
|
+
end
|
16
46
|
end
|
17
47
|
end
|
18
48
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Refinery
|
4
|
+
module Polls
|
5
|
+
describe Vote do
|
6
|
+
describe "validations" do
|
7
|
+
subject do
|
8
|
+
FactoryGirl.create(:vote)
|
9
|
+
end
|
10
|
+
|
11
|
+
it { should be_valid }
|
12
|
+
its(:errors) { should be_empty }
|
13
|
+
end
|
14
|
+
describe "class methods" do
|
15
|
+
before do
|
16
|
+
question = Factory.create(:question)
|
17
|
+
@answer = Factory.create(:answer, question: question)
|
18
|
+
@vote = Factory.create(:vote, answer: @answer)
|
19
|
+
@ip = "192.168.1.1"
|
20
|
+
end
|
21
|
+
it "should create a vote by ip for an Answer" do
|
22
|
+
vote = Vote.vote_by_ip(@answer, @ip)
|
23
|
+
vote.should be_valid
|
24
|
+
vote.ip.should == @ip
|
25
|
+
end
|
26
|
+
it "should get a vote by ip for a Question" do
|
27
|
+
Vote.get_vote(@question, @ip) == @vote
|
28
|
+
end
|
29
|
+
end
|
30
|
+
describe "instance methods" do
|
31
|
+
#nothing
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Refinery do
|
5
|
+
describe "Polls" do
|
6
|
+
describe "Admin" do
|
7
|
+
describe "Answers" do
|
8
|
+
login_refinery_user
|
9
|
+
|
10
|
+
describe "answers list" do
|
11
|
+
before(:each) do
|
12
|
+
@question = FactoryGirl.create(:question)
|
13
|
+
Factory.create(:answer, question: @question, title: "Option_1")
|
14
|
+
Factory.create(:answer, question: @question, title: "Option_2")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "shows two items" do
|
18
|
+
visit refinery.polls_admin_question_answers_path(@question)
|
19
|
+
page.should have_content("Option_1")
|
20
|
+
page.should have_content("Option_2")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "create" do
|
25
|
+
before(:each) do
|
26
|
+
@question = FactoryGirl.create(:question)
|
27
|
+
visit refinery.polls_admin_question_answers_path(@question)
|
28
|
+
|
29
|
+
click_link "Add New Question Answer"
|
30
|
+
end
|
31
|
+
|
32
|
+
context "valid data" do
|
33
|
+
it "should succeed" do
|
34
|
+
fill_in "Title", :with => "This is a test of the first string field"
|
35
|
+
click_button "Save"
|
36
|
+
|
37
|
+
page.should have_content("'This is a test of the first string field' was successfully added.")
|
38
|
+
Refinery::Polls::Answer.count.should == 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# we can't test this because admin/answers/_form.html creates wrong url helper for nested models
|
43
|
+
# context "invalid data" do
|
44
|
+
# it "should fail" do
|
45
|
+
# click_button "Save"
|
46
|
+
#
|
47
|
+
# page.should have_content("Title can't be blank")
|
48
|
+
# Refinery::Polls::Answer.count.should == 0
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
|
52
|
+
# we can't test this because admin/answers/_form.html creates wrong url helper for nested models
|
53
|
+
# context "duplicate" do
|
54
|
+
# before(:each) do
|
55
|
+
# @question = FactoryGirl.create(:question, :title => "UniqueTitle")
|
56
|
+
# Factory.create(:answer, question: @question, :title => "Option repeated")
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# it "should fail" do
|
60
|
+
# visit refinery.polls_admin_question_answers_path(@question)
|
61
|
+
#
|
62
|
+
# click_link "Add New Question Answer"
|
63
|
+
#
|
64
|
+
# fill_in "Title", :with => "Option repeated"
|
65
|
+
# click_button "Save"
|
66
|
+
#
|
67
|
+
# page.should have_content("There were problems")
|
68
|
+
# Refinery::Polls::Answer.count.should == 1
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "edit" do
|
75
|
+
before(:each) do
|
76
|
+
@question = FactoryGirl.create(:question, :title => "A title")
|
77
|
+
Factory.create(:answer, question: @question)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should succeed" do
|
81
|
+
visit refinery.polls_admin_question_answers_path(@question)
|
82
|
+
|
83
|
+
within ".actions" do
|
84
|
+
click_link "Edit this question answer"
|
85
|
+
end
|
86
|
+
|
87
|
+
fill_in "Title", :with => "A different title"
|
88
|
+
click_button "Save"
|
89
|
+
|
90
|
+
page.should have_content("'A different title' was successfully updated.")
|
91
|
+
page.should have_no_content("A title")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "destroy" do
|
96
|
+
before(:each) do
|
97
|
+
@question = FactoryGirl.create(:question, :title => "A title")
|
98
|
+
Factory.create(:answer, question: @question, title: "UniqueTitleOne")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should succeed" do
|
102
|
+
visit refinery.polls_admin_question_answers_path(@question)
|
103
|
+
|
104
|
+
click_link "Remove this question answer forever"
|
105
|
+
|
106
|
+
page.should have_content("'UniqueTitleOne' was successfully removed.")
|
107
|
+
Refinery::Polls::Answer.count.should == 0
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe Refinery do
|
5
|
+
describe "Polls" do
|
6
|
+
describe "Questions" do
|
7
|
+
login_refinery_user
|
8
|
+
|
9
|
+
describe "questions index" do
|
10
|
+
before(:each) do
|
11
|
+
FactoryGirl.create(:question, :title => "UniqueTitleTwo")
|
12
|
+
FactoryGirl.create(:question, :title => "UniqueTitleOne")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "shows two items" do
|
16
|
+
visit refinery.polls_questions_path
|
17
|
+
page.should have_content("UniqueTitleOne")
|
18
|
+
page.should have_content("UniqueTitleTwo")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
describe "question show" do
|
22
|
+
before(:each) do
|
23
|
+
@question = FactoryGirl.create(:question, :title => "UniqueTitleOne")
|
24
|
+
end
|
25
|
+
it "shows question" do
|
26
|
+
visit refinery.polls_question_path(@question)
|
27
|
+
page.should have_content(@question.title)
|
28
|
+
page.should have_content(I18n.l(@question.start_date, :format => :short))
|
29
|
+
page.should have_content(I18n.l(@question.end_date, :format => :short))
|
30
|
+
page.should have_content(@question.total_votes)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "question answer submit" do
|
35
|
+
before(:each) do
|
36
|
+
@question = FactoryGirl.create(:question, title: "submite_test")
|
37
|
+
@answers = []
|
38
|
+
3.times do |value|
|
39
|
+
@answers << Factory.create(:answer, question: @question, title: "Option #{value}")
|
40
|
+
end
|
41
|
+
ActionDispatch::Request.any_instance.stub(:remote_ip).and_return("192.168.0.1")
|
42
|
+
|
43
|
+
end
|
44
|
+
it "should save vote", :js => true do
|
45
|
+
post refinery.submit_polls_question_path(@question), :answer_id => @answers.first.id, :format=> 'js'
|
46
|
+
Refinery::Polls::Vote.count.should == 1
|
47
|
+
@answers.first.votes_count == 1
|
48
|
+
@question.total_votes.should == 1
|
49
|
+
end
|
50
|
+
it "should not save second vote from same ip", :js => true do
|
51
|
+
Factory.create(:vote, question: @question, answer: @answers.first, ip: "192.168.0.1")
|
52
|
+
#second call to submit
|
53
|
+
post refinery.submit_polls_question_path(@question), :answer_id => @answers.first.id, :format=> 'js'
|
54
|
+
Refinery::Polls::Vote.count.should == 1
|
55
|
+
@answers.first.votes_count == 1
|
56
|
+
@question.total_votes.should == 1
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
#
|
61
|
+
# describe "create" do
|
62
|
+
# before(:each) do
|
63
|
+
# visit refinery.polls_admin_questions_path
|
64
|
+
#
|
65
|
+
# click_link "Add New Question"
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# context "valid data" do
|
69
|
+
# it "should succeed" do
|
70
|
+
# fill_in "Title", :with => "This is a test of the first string field"
|
71
|
+
# click_button "Save"
|
72
|
+
#
|
73
|
+
# page.should have_content("'This is a test of the first string field' was successfully added.")
|
74
|
+
# Refinery::Polls::Question.count.should == 1
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# context "invalid data" do
|
79
|
+
# it "should fail" do
|
80
|
+
# click_button "Save"
|
81
|
+
#
|
82
|
+
# page.should have_content("Title can't be blank")
|
83
|
+
# Refinery::Polls::Question.count.should == 0
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# context "duplicate" do
|
88
|
+
# before(:each) { FactoryGirl.create(:question, :title => "UniqueTitle") }
|
89
|
+
#
|
90
|
+
# it "should fail" do
|
91
|
+
# visit refinery.polls_admin_questions_path
|
92
|
+
#
|
93
|
+
# click_link "Add New Question"
|
94
|
+
#
|
95
|
+
# fill_in "Title", :with => "UniqueTitle"
|
96
|
+
# click_button "Save"
|
97
|
+
#
|
98
|
+
# page.should have_content("There were problems")
|
99
|
+
# Refinery::Polls::Question.count.should == 1
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# describe "edit" do
|
106
|
+
# before(:each) { FactoryGirl.create(:question, :title => "A title") }
|
107
|
+
#
|
108
|
+
# it "should succeed" do
|
109
|
+
# visit refinery.polls_admin_questions_path
|
110
|
+
#
|
111
|
+
# within ".actions" do
|
112
|
+
# click_link "Edit this question"
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# fill_in "Title", :with => "A different title"
|
116
|
+
# click_button "Save"
|
117
|
+
#
|
118
|
+
# page.should have_content("'A different title' was successfully updated.")
|
119
|
+
# page.should have_no_content("A title")
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# describe "destroy" do
|
124
|
+
# before(:each) { FactoryGirl.create(:question, :title => "UniqueTitleOne") }
|
125
|
+
#
|
126
|
+
# it "should succeed" do
|
127
|
+
# visit refinery.polls_admin_questions_path
|
128
|
+
#
|
129
|
+
# click_link "Remove this question forever"
|
130
|
+
#
|
131
|
+
# page.should have_content("'UniqueTitleOne' was successfully removed.")
|
132
|
+
# Refinery::Polls::Question.count.should == 0
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
-
|
2
1
|
FactoryGirl.define do
|
3
|
-
factory :question,
|
2
|
+
factory :question, :class => Refinery::Polls::Question do
|
4
3
|
sequence(:title) { |n| "refinery#{n}" }
|
4
|
+
start_date Time.now-10.days
|
5
|
+
end_date Time.now+10.days
|
6
|
+
end
|
7
|
+
factory :answer, :class => Refinery::Polls::Answer do
|
8
|
+
sequence(:title) { |n| "refinery-answer#{n}" }
|
9
|
+
association :question, :factory => :question
|
10
|
+
end
|
11
|
+
factory :vote, :class => Refinery::Polls::Vote do
|
12
|
+
association :question, :factory => :question
|
13
|
+
association :answer, :factory => :answer
|
14
|
+
sequence(:ip) { |n| "127.0.1.#{n}" }
|
5
15
|
end
|
6
16
|
end
|
7
17
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: refinerycms-polls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4.dev
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -66,13 +66,16 @@ extensions: []
|
|
66
66
|
extra_rdoc_files: []
|
67
67
|
files:
|
68
68
|
- .gitignore
|
69
|
+
- CHANGELOG.md
|
69
70
|
- Gemfile
|
70
71
|
- Guardfile
|
71
72
|
- README.md
|
72
73
|
- Rakefile
|
73
74
|
- app/assets/images/refinery/polls/pollbg.gif
|
74
|
-
- app/assets/javascripts/refinery/polls/
|
75
|
+
- app/assets/javascripts/refinery/polls/poll.js
|
76
|
+
- app/assets/javascripts/refinery/polls/poll_form.js.coffee
|
75
77
|
- app/assets/stylesheets/refinery/polls/poll_form.css.scss
|
78
|
+
- app/assets/stylesheets/refinery/polls/polls.css.scss
|
76
79
|
- app/controllers/refinery/polls/admin/answers_controller.rb
|
77
80
|
- app/controllers/refinery/polls/admin/questions_controller.rb
|
78
81
|
- app/controllers/refinery/polls/questions_controller.rb
|
@@ -118,6 +121,7 @@ files:
|
|
118
121
|
- db/migrate/5_create_polls_translations.rb
|
119
122
|
- db/seeds.rb
|
120
123
|
- lib/generators/refinery/polls_generator.rb
|
124
|
+
- lib/generators/refinery/templates/app/assets/stylesheets/refinery/polls/poll.css.scss
|
121
125
|
- lib/generators/refinery/templates/config/initializers/refinery/poll.rb.erb
|
122
126
|
- lib/refinery/polls.rb
|
123
127
|
- lib/refinery/polls/configuration.rb
|
@@ -126,8 +130,12 @@ files:
|
|
126
130
|
- lib/refinerycms-polls.rb
|
127
131
|
- lib/tasks/refinery/polls.rake
|
128
132
|
- refinerycms-polls.gemspec
|
133
|
+
- spec/models/refinery/polls/answer_spec.rb
|
129
134
|
- spec/models/refinery/polls/question_spec.rb
|
135
|
+
- spec/models/refinery/polls/vote_spec.rb
|
136
|
+
- spec/requests/refinery/polls/admin/answers_spec.rb
|
130
137
|
- spec/requests/refinery/polls/admin/questions_spec.rb
|
138
|
+
- spec/requests/refinery/polls/questions_spec.rb
|
131
139
|
- spec/spec_helper.rb
|
132
140
|
- spec/support/factories/refinery/polls.rb
|
133
141
|
- tasks/rspec.rake
|
@@ -146,6 +154,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
154
|
- - ! '>='
|
147
155
|
- !ruby/object:Gem::Version
|
148
156
|
version: '0'
|
157
|
+
segments:
|
158
|
+
- 0
|
159
|
+
hash: -252205175820330906
|
149
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
161
|
none: false
|
151
162
|
requirements:
|
@@ -159,7 +170,11 @@ signing_key:
|
|
159
170
|
specification_version: 3
|
160
171
|
summary: Polls extension for Refinery CMS
|
161
172
|
test_files:
|
173
|
+
- spec/models/refinery/polls/answer_spec.rb
|
162
174
|
- spec/models/refinery/polls/question_spec.rb
|
175
|
+
- spec/models/refinery/polls/vote_spec.rb
|
176
|
+
- spec/requests/refinery/polls/admin/answers_spec.rb
|
163
177
|
- spec/requests/refinery/polls/admin/questions_spec.rb
|
178
|
+
- spec/requests/refinery/polls/questions_spec.rb
|
164
179
|
- spec/spec_helper.rb
|
165
180
|
- spec/support/factories/refinery/polls.rb
|