biovision-poll 0.0.170908 → 0.1.180917.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/app/controllers/admin/poll_answers_controller.rb +1 -0
  3. data/app/controllers/admin/poll_questions_controller.rb +1 -0
  4. data/app/controllers/admin/polls_controller.rb +23 -0
  5. data/app/controllers/poll_answers_controller.rb +5 -5
  6. data/app/controllers/poll_questions_controller.rb +5 -5
  7. data/app/controllers/polls_controller.rb +36 -8
  8. data/app/helpers/polls_helper.rb +8 -3
  9. data/app/models/poll.rb +64 -5
  10. data/app/models/poll_answer.rb +5 -0
  11. data/app/models/poll_question.rb +4 -0
  12. data/app/models/poll_user.rb +10 -0
  13. data/app/views/admin/index/dashboard/_biovision_poll.html.erb +10 -0
  14. data/app/views/admin/poll_answers/entity/_in_list.html.erb +11 -12
  15. data/app/views/admin/poll_answers/show.html.erb +2 -2
  16. data/app/views/admin/poll_questions/entity/_in_list.html.erb +29 -8
  17. data/app/views/admin/poll_questions/show.html.erb +17 -4
  18. data/app/views/admin/poll_users/entity/_in_list.html.erb +18 -0
  19. data/app/views/admin/polls/_nav_item.html.erb +2 -6
  20. data/app/views/admin/polls/entity/_in_list.html.erb +30 -6
  21. data/app/views/admin/polls/entity/_user_filter.html.erb +85 -0
  22. data/app/views/admin/polls/show.html.erb +48 -17
  23. data/app/views/admin/polls/users.html.erb +21 -0
  24. data/app/views/admin/polls/users.jbuilder +10 -0
  25. data/app/views/poll_answers/_form.html.erb +39 -37
  26. data/app/views/poll_answers/_poll_answer.html.erb +6 -0
  27. data/app/views/poll_answers/edit.html.erb +1 -1
  28. data/app/views/poll_answers/new.html.erb +1 -1
  29. data/app/views/poll_questions/_form.html.erb +55 -47
  30. data/app/views/poll_questions/_poll_question.html.erb +10 -0
  31. data/app/views/poll_questions/edit.html.erb +1 -1
  32. data/app/views/poll_questions/new.html.erb +1 -1
  33. data/app/views/polls/_form.html.erb +49 -39
  34. data/app/views/polls/_list.html.erb +11 -0
  35. data/app/views/polls/_poll.html.erb +22 -0
  36. data/app/views/polls/edit.html.erb +1 -1
  37. data/app/views/polls/entity/_in_list.html.erb +20 -0
  38. data/app/views/polls/index.html.erb +9 -0
  39. data/app/views/polls/results.html.erb +6 -0
  40. data/app/views/polls/show.html.erb +3 -0
  41. data/config/locales/polls-ru.yml +36 -2
  42. data/config/routes.rb +27 -10
  43. data/db/migrate/20170906000001_create_polls.rb +19 -6
  44. data/db/migrate/20170906000002_create_poll_questions.rb +1 -1
  45. data/db/migrate/20170906000003_create_poll_answers.rb +1 -1
  46. data/db/migrate/20170906000004_create_poll_votes.rb +2 -2
  47. data/db/migrate/20180412000010_create_poll_users.rb +21 -0
  48. data/db/migrate/20180903111111_rename_vote_footprint.rb +11 -0
  49. data/lib/biovision/poll/engine.rb +10 -6
  50. data/lib/biovision/poll/version.rb +1 -1
  51. metadata +20 -6
  52. data/app/views/admin/poll_questions/_toggleable.html.erb +0 -7
  53. data/app/views/admin/polls/_toggleable.html.erb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a178bf343ce1bc3f702577d444db93e3efdd58e6
4
- data.tar.gz: 2997c450eb8e26ea18da19910aef9f1e9f5c0698
2
+ SHA256:
3
+ metadata.gz: e673d23a9adf4f6fd8b9a31e41d117bc29cd0821a687e4b5a650f83cbe400035
4
+ data.tar.gz: dca9cfa8d1ab77d328e39ee1930b4a24112f0dca08695a45d8a22ad13239216a
5
5
  SHA512:
6
- metadata.gz: 8f5217cc9b0e0bb6a367da4dddab9ed70fa88e9fbfd79f2a6e7d1f0e79fa5b4846697200b3fed8a99414718bc5ff175e2eac6474ac7ed4c65e22bcb7f2ef593d
7
- data.tar.gz: 45ba435cc521559641c5eb4e86d19878d8e32d92e8b22971ccb9596a3620214a05992676b51c7f4bb8df471739f3efc83e123fbee62a4fcf35093fa0b3b05ff5
6
+ metadata.gz: 2b2e12f2d66ab1451ec17c5b5190a85a5f993b59bede884793e5cff0b37435dae42fa28844e5fc23c288e41ab0b22b1adb14f953b94bfbb77b5be06852b0e338
7
+ data.tar.gz: acde6ad3f720aedec127251e1a0e78824240220ff70fefcd554c57beb990eab5a1b98e0f5b6e541f98be3a0c5985d8a1621738e9690c8f518da3e4a344441208
@@ -1,5 +1,6 @@
1
1
  class Admin::PollAnswersController < AdminController
2
2
  include ToggleableEntity
3
+ include EntityPriority
3
4
 
4
5
  before_action :set_entity
5
6
 
@@ -1,5 +1,6 @@
1
1
  class Admin::PollQuestionsController < AdminController
2
2
  include ToggleableEntity
3
+ include EntityPriority
3
4
 
4
5
  before_action :set_entity
5
6
 
@@ -12,6 +12,29 @@ class Admin::PollsController < AdminController
12
12
  def show
13
13
  end
14
14
 
15
+ # get /admin/polls/:id/users
16
+ def users
17
+ @collection = @entity.poll_users.list_for_administration
18
+ end
19
+
20
+ # post /admin/polls/:id/users
21
+ def add_user
22
+ user = User.find_by(id: params[:user_id])
23
+
24
+ @entity.add_user(user) unless user.nil?
25
+
26
+ render :users
27
+ end
28
+
29
+ # delete /admin/polls/:id/users/:user_id
30
+ def remove_user
31
+ user = User.find_by(id: params[:user_id])
32
+
33
+ @entity.remove_user(user) unless user.nil?
34
+
35
+ render :users
36
+ end
37
+
15
38
  private
16
39
 
17
40
  def restrict_access
@@ -5,9 +5,9 @@ class PollAnswersController < AdminController
5
5
  def create
6
6
  @entity = PollAnswer.new(creation_parameters)
7
7
  if @entity.save
8
- redirect_to admin_poll_answer_path(@entity.id)
8
+ form_processed_ok(admin_poll_question_path(id: @entity.poll_question_id))
9
9
  else
10
- render :new, status: :bad_request
10
+ form_processed_with_error(:new)
11
11
  end
12
12
  end
13
13
 
@@ -18,9 +18,9 @@ class PollAnswersController < AdminController
18
18
  # patch /poll_answers/:id
19
19
  def update
20
20
  if @entity.update(entity_parameters)
21
- redirect_to admin_poll_answer_path(@entity.id), notice: t('poll_answers.update.success')
21
+ form_processed_ok(admin_poll_question_path(id: @entity.poll_question_id))
22
22
  else
23
- render :edit, status: :bad_request
23
+ form_processed_with_error(:edit)
24
24
  end
25
25
  end
26
26
 
@@ -29,7 +29,7 @@ class PollAnswersController < AdminController
29
29
  if @entity.destroy
30
30
  flash[:notice] = t('poll_answers.destroy.success')
31
31
  end
32
- redirect_to(admin_poll_path(@entity.id))
32
+ redirect_to(admin_poll_question_path(id: @entity.poll_question_id))
33
33
  end
34
34
 
35
35
  protected
@@ -5,9 +5,9 @@ class PollQuestionsController < AdminController
5
5
  def create
6
6
  @entity = PollQuestion.new(creation_parameters)
7
7
  if @entity.save
8
- redirect_to admin_poll_question_path(@entity.id)
8
+ form_processed_ok(admin_poll_question_path(id: @entity.id))
9
9
  else
10
- render :new, status: :bad_request
10
+ form_processed_with_error(:new)
11
11
  end
12
12
  end
13
13
 
@@ -18,9 +18,9 @@ class PollQuestionsController < AdminController
18
18
  # patch /poll_questions/:id
19
19
  def update
20
20
  if @entity.update(entity_parameters)
21
- redirect_to admin_poll_question_path(@entity.id), notice: t('poll_questions.update.success')
21
+ form_processed_ok(admin_poll_question_path(id: @entity.id))
22
22
  else
23
- render :edit, status: :bad_request
23
+ form_processed_with_error(:edit)
24
24
  end
25
25
  end
26
26
 
@@ -29,7 +29,7 @@ class PollQuestionsController < AdminController
29
29
  if @entity.destroy
30
30
  flash[:notice] = t('poll_questions.destroy.success')
31
31
  end
32
- redirect_to(admin_poll_path(@entity.poll_id))
32
+ redirect_to(admin_poll_path(id: @entity.poll_id))
33
33
  end
34
34
 
35
35
  protected
@@ -1,8 +1,13 @@
1
1
  class PollsController < ApplicationController
2
- before_action :restrict_access, except: [:index, :show]
3
- before_action :set_entity, only: [:edit, :update, :destroy]
2
+ before_action :restrict_access, except: [:index, :show, :results, :answer]
3
+ before_action :set_entity, except: [:index, :new, :create]
4
4
 
5
- layout 'admin', except: [:index, :show]
5
+ layout 'admin', except: [:index, :show, :results]
6
+
7
+ # get /polls
8
+ def index
9
+ @collection = Poll.page_for_visitors(current_page)
10
+ end
6
11
 
7
12
  # get /polls/new
8
13
  def new
@@ -11,11 +16,18 @@ class PollsController < ApplicationController
11
16
 
12
17
  # post /polls
13
18
  def create
14
- @entity = Poll.new(entity_parameters)
19
+ @entity = Poll.new(creation_parameters)
15
20
  if @entity.save
16
- redirect_to(admin_poll_path(@entity.id))
21
+ form_processed_ok(admin_poll_path(id: @entity.id))
17
22
  else
18
- render :new, status: :bad_request
23
+ form_processed_with_error(:new)
24
+ end
25
+ end
26
+
27
+ # get /polls/:id
28
+ def show
29
+ unless @entity.visible_to?(current_user)
30
+ redirect_to polls_path
19
31
  end
20
32
  end
21
33
 
@@ -26,9 +38,9 @@ class PollsController < ApplicationController
26
38
  # patch /polls/:id
27
39
  def update
28
40
  if @entity.update(entity_parameters)
29
- redirect_to admin_poll_path(@entity), notice: t('polls.update.success')
41
+ form_processed_ok(admin_poll_path(id: @entity.id))
30
42
  else
31
- render :edit, status: :bad_request
43
+ form_processed_with_error(:edit)
32
44
  end
33
45
  end
34
46
 
@@ -40,6 +52,18 @@ class PollsController < ApplicationController
40
52
  redirect_to(admin_polls_path)
41
53
  end
42
54
 
55
+ # post /polls/:id/results
56
+ def answer
57
+ @entity.process_answers(current_user, params.require(:answer))
58
+
59
+ redirect_to root_path(id: @entity.id)
60
+ end
61
+
62
+ # get /polls/:id/results
63
+ def results
64
+ redirect_to poll_path(id: @entity.id) unless @entity.show_results?(current_user)
65
+ end
66
+
43
67
  protected
44
68
 
45
69
  def restrict_access
@@ -56,4 +80,8 @@ class PollsController < ApplicationController
56
80
  def entity_parameters
57
81
  params.require(:poll).permit(Poll.entity_parameters)
58
82
  end
83
+
84
+ def creation_parameters
85
+ entity_parameters.merge(owner_for_entity(true))
86
+ end
59
87
  end
@@ -1,17 +1,22 @@
1
1
  module PollsHelper
2
2
  # @param [Poll] entity
3
3
  def admin_poll_link(entity)
4
- link_to(entity.name, admin_poll_path(entity.id))
4
+ link_to(entity.name, admin_poll_path(id: entity.id))
5
5
  end
6
6
 
7
7
  # @param [PollQuestion] entity
8
8
  def admin_poll_question_link(entity)
9
- link_to(entity.text, admin_poll_question_path(entity.id))
9
+ link_to(entity.text, admin_poll_question_path(id: entity.id))
10
+ end
11
+
12
+ # @param [PollAnswer] entity
13
+ def admin_poll_answer_link(entity)
14
+ link_to(entity.text, admin_poll_answer_path(id: entity.id))
10
15
  end
11
16
 
12
17
  # @param [Poll] entity
13
18
  def poll_link(entity)
14
- link_to(entity.name, poll_path(entity.id))
19
+ link_to(entity.name, poll_path(id: entity.id))
15
20
  end
16
21
 
17
22
  # @param [Poll] entity
data/app/models/poll.rb CHANGED
@@ -6,23 +6,24 @@ class Poll < ApplicationRecord
6
6
  NAME_LIMIT = 140
7
7
  DESCRIPTION_LIMIT = 255
8
8
 
9
- toggleable %i(active anonymous_votes open_results show_on_homepage visible)
9
+ toggleable %i[active anonymous_votes open_results show_on_homepage visible exclusive]
10
10
 
11
11
  mount_uploader :image, PollImageUploader
12
12
 
13
13
  belongs_to :user
14
14
  belongs_to :agent, optional: true
15
- belongs_to :region, optional: true
16
- belongs_to :pollable, polymorphic: true
15
+ belongs_to :region, optional: true if Gem.loaded_specs.key?('biovision-regions')
16
+ belongs_to :pollable, polymorphic: true, optional: true
17
17
  has_many :poll_questions, dependent: :delete_all
18
+ has_many :poll_users, dependent: :delete_all
18
19
 
19
- validates_presence_of :name, :description
20
+ validates_presence_of :name
20
21
  validates_length_of :name, maximum: NAME_LIMIT
21
22
  validates_length_of :description, maximum: DESCRIPTION_LIMIT
22
23
 
23
24
  scope :recent, -> { order('id desc') }
24
25
  scope :visible, -> { where(visible: true) }
25
- scope :active, -> { where(active: true).where('end_date >= now() or end_date is null') }
26
+ scope :active, -> { visible.where('active = true and (end_date is null or (date(end_date) >= date(now())))') }
26
27
 
27
28
  # @param [Integer] page
28
29
  def self.page_for_administration(page = 1)
@@ -50,7 +51,65 @@ class Poll < ApplicationRecord
50
51
  visible? || owned_by?(user)
51
52
  end
52
53
 
54
+ # @param [User] user
55
+ def votable_by?(user)
56
+ return false if user.nil? || voted?(user)
57
+ if exclusive?
58
+ includes?(user)
59
+ # elsif anonymous_votes?
60
+ else
61
+ true
62
+ end
63
+ end
64
+
65
+ # @param [User] user
66
+ def voted?(user)
67
+ PollVote.where(poll_answer_id: answer_ids, user: user).exists?
68
+ end
69
+
70
+ # @param [User] user
71
+ def show_results?(user)
72
+ open_results? || editable_by?(user)
73
+ end
74
+
53
75
  def regional?
54
76
  !region_id.nil?
55
77
  end
78
+
79
+ # @param [User] user
80
+ def includes?(user)
81
+ poll_users.owned_by(user).exists?
82
+ end
83
+
84
+ # @param [User] user
85
+ def add_user(user)
86
+ PollUser.create(poll: self, user: user)
87
+ end
88
+
89
+ # @param [User] user
90
+ def remove_user(user)
91
+ poll_users.owned_by(user).delete_all
92
+ end
93
+
94
+ def answer_ids
95
+ PollAnswer.where(poll_question_id: poll_questions.pluck(:id)).pluck(:id)
96
+ end
97
+
98
+ # @param [User] user
99
+ # @param [Hash] answers
100
+ def process_answers(user, answers)
101
+ return unless votable_by?(user)
102
+ answers.each do |question_id, answer_ids|
103
+ question = PollQuestion.find_by(id: question_id)
104
+ next if question.nil? || question.poll_id != id
105
+ if question.multiple_choice?
106
+ answers = question.poll_answers.where(id: answer_ids)
107
+ else
108
+ answers = question.poll_answers.where(id: answer_ids.first)
109
+ end
110
+ answers.each do |answer|
111
+ PollVote.create(poll_answer: answer, user: user)
112
+ end
113
+ end
114
+ end
56
115
  end
@@ -1,5 +1,6 @@
1
1
  class PollAnswer < ApplicationRecord
2
2
  TEXT_LIMIT = 140
3
+ PRIORITY_RANGE = (1..50)
3
4
 
4
5
  mount_uploader :image, PollImageUploader
5
6
 
@@ -35,6 +36,10 @@ class PollAnswer < ApplicationRecord
35
36
  poll_question&.poll
36
37
  end
37
38
 
39
+ def vote_percent
40
+ poll_votes_count.to_f / poll_question.vote_count * 100
41
+ end
42
+
38
43
  # @param [Integer] delta
39
44
  def change_priority(delta)
40
45
  new_priority = priority + delta
@@ -38,6 +38,10 @@ class PollQuestion < ApplicationRecord
38
38
  poll.editable_by?(user)
39
39
  end
40
40
 
41
+ def vote_count
42
+ poll_answers.pluck(:poll_votes_count).reduce(&:+)
43
+ end
44
+
41
45
  # @param [Integer] delta
42
46
  def change_priority(delta)
43
47
  new_priority = priority + delta
@@ -0,0 +1,10 @@
1
+ class PollUser < ApplicationRecord
2
+ include HasOwner
3
+
4
+ belongs_to :poll
5
+ belongs_to :user
6
+
7
+ validates_uniqueness_of :user_id, scope: [:poll_id]
8
+
9
+ scope :list_for_administration, -> { order('id desc') }
10
+ end
@@ -0,0 +1,10 @@
1
+ <% if current_user_in_group?(:poll_managers) %>
2
+ <nav>
3
+ <div class="heading" id="biovision-poll-nav-heading">
4
+ <%= t('.heading') %>
5
+ </div>
6
+ <ul aria-labelledby="biovision-poll-nav-heading">
7
+ <li><%= render 'admin/polls/nav_item' %></li>
8
+ </ul>
9
+ </nav>
10
+ <% end %>
@@ -2,19 +2,18 @@
2
2
  <%= poll_image_preview(entity) %>
3
3
  </div>
4
4
  <div class="data">
5
- <div><%= admin_poll_question_link(entity) %></div>
6
- <% unless entity.comment.blank? %>
7
- <div class="info">
8
- <%= entity.comment %>
9
- </div>
10
- <% end %>
11
- <% if entity.poll_answers.any? %>
12
- <div><%= entity.poll_answers.count %></div>
13
- <% end %>
14
-
15
- <%= redner partial: 'admin/polls/toggleable', locals: { entity: entity } %>
5
+ <div><%= admin_poll_answer_link(entity) %></div>
6
+ <div class="secondary info">
7
+ <%= t(:poll_vote_count, count: entity.poll_votes_count) %>
8
+ </div>
16
9
 
17
10
  <ul class="actions">
18
- <li><%= edit_icon(edit_poll_path(entity)) %></li>
11
+ <li><%= edit_icon(edit_poll_answer_path(id: entity.id)) %></li>
12
+ <%=
13
+ render(
14
+ partial: 'shared/actions/priority_changer',
15
+ locals: { path: priority_admin_poll_answer_path(id: entity.id) }
16
+ )
17
+ %>
19
18
  </ul>
20
19
  </div>
@@ -10,8 +10,8 @@
10
10
  <h1><%= @entity.text %></h1>
11
11
 
12
12
  <ul class="actions">
13
- <li><%= return_icon(admin_poll_question_path(@entity.poll_question_id)) %></li>
14
- <li><%= edit_icon(edit_poll_answer_path(@entity.id)) %></li>
13
+ <li><%= return_icon(admin_poll_question_path(id: @entity.poll_question_id)) %></li>
14
+ <li><%= edit_icon(edit_poll_answer_path(id: @entity.id)) %></li>
15
15
  </ul>
16
16
 
17
17
  <% unless @entity.image.blank? %>
@@ -4,17 +4,38 @@
4
4
  <div class="data">
5
5
  <div><%= admin_poll_question_link(entity) %></div>
6
6
  <% unless entity.comment.blank? %>
7
- <div class="info">
8
- <%= entity.comment %>
9
- </div>
10
- <% end %>
11
- <% if entity.poll_answers.any? %>
12
- <div><%= entity.poll_answers.count %></div>
7
+ <div class="info">
8
+ <%= entity.comment %>
9
+ </div>
13
10
  <% end %>
11
+ <div class="secondary info">
12
+ <%= t(:poll_answer_count, count: entity.poll_answers_count) %>
13
+ <% if entity.poll_answers.any? %>
14
+ <ol>
15
+ <% entity.poll_answers.ordered_by_priority.each do |answer| %>
16
+ <li><%= admin_poll_answer_link(answer) %></li>
17
+ <% end %>
18
+ </ol>
19
+ <% end %>
20
+ </div>
14
21
 
15
- <%= redner partial: 'admin/polls/toggleable', locals: { entity: entity } %>
22
+ <%=
23
+ render(
24
+ partial: 'shared/admin/toggleable',
25
+ locals: {
26
+ entity: entity,
27
+ url: toggle_admin_poll_question_path(id: entity.id)
28
+ }
29
+ )
30
+ %>
16
31
 
17
32
  <ul class="actions">
18
- <li><%= edit_icon(edit_poll_path(entity)) %></li>
33
+ <li><%= edit_icon(edit_poll_question_path(id: entity.id)) %></li>
34
+ <%=
35
+ render(
36
+ partial: 'shared/actions/priority_changer',
37
+ locals: { path: priority_admin_poll_question_path(id: entity.id) }
38
+ )
39
+ %>
19
40
  </ul>
20
41
  </div>