biovision-poll 0.1.180917.0 → 0.2.200324.1

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 +4 -4
  2. data/app/controllers/admin/poll_answers_controller.rb +6 -5
  3. data/app/controllers/admin/poll_questions_controller.rb +6 -5
  4. data/app/controllers/admin/polls_controller.rb +7 -6
  5. data/app/controllers/poll_answers_controller.rb +15 -9
  6. data/app/controllers/poll_questions_controller.rb +15 -9
  7. data/app/controllers/polls_controller.rb +25 -16
  8. data/app/helpers/polls_helper.rb +19 -29
  9. data/app/models/poll.rb +50 -18
  10. data/app/models/poll_answer.rb +29 -36
  11. data/app/models/poll_question.rb +33 -39
  12. data/app/models/poll_user.rb +10 -1
  13. data/app/models/poll_vote.rb +20 -5
  14. data/app/services/biovision/components/polls_component.rb +21 -0
  15. data/app/views/admin/components/links/_polls.html.erb +1 -0
  16. data/app/views/admin/poll_answers/entity/_data.html.erb +0 -0
  17. data/app/views/admin/poll_answers/entity/_in_list.html.erb +0 -3
  18. data/app/views/admin/poll_answers/show.html.erb +25 -35
  19. data/app/views/admin/poll_questions/entity/_data.html.erb +0 -0
  20. data/app/views/admin/poll_questions/entity/_in_list.html.erb +6 -5
  21. data/app/views/admin/poll_questions/show.html.erb +29 -37
  22. data/app/views/admin/poll_votes/entity/_data.html.erb +0 -0
  23. data/app/views/admin/poll_votes/entity/_in_list.html.erb +6 -5
  24. data/app/views/admin/polls/entity/_data.html.erb +0 -0
  25. data/app/views/admin/polls/entity/_in_list.html.erb +1 -3
  26. data/app/views/admin/polls/index.html.erb +8 -2
  27. data/app/views/admin/polls/show.html.erb +32 -30
  28. data/app/views/admin/polls/users.html.erb +2 -1
  29. data/app/views/poll_answers/_form.html.erb +36 -30
  30. data/app/views/poll_answers/_poll_answer.html.erb +22 -2
  31. data/app/views/poll_answers/edit.html.erb +6 -5
  32. data/app/views/poll_answers/new.html.erb +8 -7
  33. data/app/views/poll_questions/_form.html.erb +53 -43
  34. data/app/views/poll_questions/edit.html.erb +6 -5
  35. data/app/views/poll_questions/new.html.erb +7 -6
  36. data/app/views/polls/_form.html.erb +64 -41
  37. data/app/views/polls/_poll.html.erb +11 -6
  38. data/app/views/polls/edit.html.erb +5 -4
  39. data/app/views/polls/new.html.erb +3 -2
  40. data/app/views/polls/results.html.erb +22 -0
  41. data/config/locales/polls-ru.yml +28 -26
  42. data/config/routes.rb +19 -15
  43. data/db/migrate/20200323000001_create_biovision_polls.rb +121 -0
  44. data/lib/biovision/poll/version.rb +3 -1
  45. metadata +10 -12
  46. data/app/uploaders/poll_image_uploader.rb +0 -46
  47. data/app/views/admin/index/dashboard/_biovision_poll.html.erb +0 -10
  48. data/db/migrate/20170906000001_create_polls.rb +0 -70
  49. data/db/migrate/20170906000002_create_poll_questions.rb +0 -22
  50. data/db/migrate/20170906000003_create_poll_answers.rb +0 -20
  51. data/db/migrate/20170906000004_create_poll_votes.rb +0 -20
  52. data/db/migrate/20180412000010_create_poll_users.rb +0 -21
  53. data/db/migrate/20180903111111_rename_vote_footprint.rb +0 -11
@@ -1,30 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Answer to poll question
4
+ #
5
+ # Attributes:
6
+ # created_at [DateTime]
7
+ # data [jsonb]
8
+ # poll_question_id [PollQuestion]
9
+ # poll_votes_count [integer]
10
+ # priority [integer]
11
+ # simple_image_id [SimpleImage], optional
12
+ # text [string]
13
+ # updated_at [DateTime]
14
+ # uuid [uuid]
1
15
  class PollAnswer < ApplicationRecord
2
- TEXT_LIMIT = 140
3
- PRIORITY_RANGE = (1..50)
16
+ include Checkable
17
+ include HasSimpleImage
18
+ include HasUuid
19
+ include NestedPriority
4
20
 
5
- mount_uploader :image, PollImageUploader
21
+ TEXT_LIMIT = 140
6
22
 
7
23
  belongs_to :poll_question, counter_cache: true
8
24
  has_many :poll_votes, dependent: :delete_all
9
25
 
10
- after_initialize :set_next_priority
11
-
12
26
  before_validation { self.text = text.to_s.strip }
13
- before_validation :normalize_priority
14
27
 
15
28
  validates_presence_of :text
16
29
  validates_length_of :text, maximum: TEXT_LIMIT
17
- validates_uniqueness_of :text, scope: [:poll_question_id]
30
+ validates_uniqueness_of :text, scope: :poll_question_id
18
31
 
19
- scope :ordered_by_priority, -> { order('priority asc, text asc') }
20
- scope :siblings, ->(item) { where(poll_question_id: item.poll_question_id) }
32
+ scope :list_for_visitors, -> { ordered_by_priority }
33
+ scope :list_for_administration, -> { ordered_by_priority }
34
+
35
+ # @param [PollAnswer] entity
36
+ def self.siblings(entity)
37
+ where(poll_question_id: entity&.poll_question_id)
38
+ end
21
39
 
22
40
  def self.entity_parameters
23
- %i(image text)
41
+ %i[text simple_image_id]
24
42
  end
25
43
 
26
44
  def self.creation_parameters
27
- entity_parameters + %i(poll_question_id)
45
+ entity_parameters + %i[poll_question_id]
28
46
  end
29
47
 
30
48
  # @param [User] user
@@ -39,29 +57,4 @@ class PollAnswer < ApplicationRecord
39
57
  def vote_percent
40
58
  poll_votes_count.to_f / poll_question.vote_count * 100
41
59
  end
42
-
43
- # @param [Integer] delta
44
- def change_priority(delta)
45
- new_priority = priority + delta
46
- adjacent = self.class.siblings(self).find_by(priority: new_priority)
47
- if adjacent.is_a?(self.class) && (adjacent.id != id)
48
- adjacent.update!(priority: priority)
49
- end
50
- update(priority: new_priority)
51
-
52
- self.class.siblings(self).map { |e| [e.id, e.priority] }.to_h
53
- end
54
-
55
- private
56
-
57
- def set_next_priority
58
- if id.nil? && priority == 1
59
- self.priority = self.class.siblings(self).maximum(:priority).to_i + 1
60
- end
61
- end
62
-
63
- def normalize_priority
64
- self.priority = PRIORITY_RANGE.first if priority < PRIORITY_RANGE.first
65
- self.priority = PRIORITY_RANGE.last if priority > PRIORITY_RANGE.last
66
- end
67
60
  end
@@ -1,36 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Poll question
4
+ #
5
+ # Attributes:
6
+ # comment [string], optional
7
+ # created_at [DateTime]
8
+ # data [jsonb]
9
+ # multiple_choice [boolean]
10
+ # poll_answers_count [integer]
11
+ # poll_id [Poll]
12
+ # priority [integer]
13
+ # simple_image_id [SimpleImage], optional
14
+ # text [string]
15
+ # updated_at [DateTime]
16
+ # uuid [uuid]
1
17
  class PollQuestion < ApplicationRecord
18
+ include Checkable
19
+ include HasSimpleImage
20
+ include HasUuid
21
+ include NestedPriority
2
22
  include Toggleable
3
23
 
4
- TEXT_LIMIT = 140
5
- COMMENT_LIMIT = 140
6
- PRIORITY_RANGE = (1..100)
24
+ COMMENT_LIMIT = 255
25
+ TEXT_LIMIT = 255
7
26
 
8
27
  toggleable :multiple_choice
9
28
 
10
- mount_uploader :image, PollImageUploader
11
-
12
29
  belongs_to :poll, counter_cache: true
13
30
  has_many :poll_answers, dependent: :delete_all
14
31
 
15
- after_initialize :set_next_priority
16
-
17
32
  before_validation { self.text = text.to_s.strip }
18
- before_validation :normalize_priority
19
33
 
20
34
  validates_presence_of :text
21
35
  validates_length_of :text, maximum: TEXT_LIMIT
22
36
  validates_length_of :comment, maximum: COMMENT_LIMIT
23
- validates_uniqueness_of :text, scope: [:poll_id]
37
+ validates_uniqueness_of :text, scope: :poll_id
38
+
39
+ scope :list_for_visitors, -> { ordered_by_priority }
40
+ scope :list_for_administration, -> { ordered_by_priority }
24
41
 
25
- scope :ordered_by_priority, -> { order('priority asc, text asc') }
26
- scope :siblings, ->(item) { where(poll_id: item.poll_id) }
42
+ # @param [PollQuestion] entity
43
+ def self.siblings(entity)
44
+ where(poll_id: entity&.poll_id)
45
+ end
27
46
 
28
47
  def self.entity_parameters
29
- PollQuestion.toggleable_attributes + %i(image text comment)
48
+ PollQuestion.toggleable_attributes + %i[comment simple_image_id text]
30
49
  end
31
50
 
32
51
  def self.creation_parameters
33
- entity_parameters + %i(poll_id)
52
+ entity_parameters + %i[poll_id]
34
53
  end
35
54
 
36
55
  # @param [User] user
@@ -39,31 +58,6 @@ class PollQuestion < ApplicationRecord
39
58
  end
40
59
 
41
60
  def vote_count
42
- poll_answers.pluck(:poll_votes_count).reduce(&:+)
43
- end
44
-
45
- # @param [Integer] delta
46
- def change_priority(delta)
47
- new_priority = priority + delta
48
- adjacent = self.class.siblings(self).find_by(priority: new_priority)
49
- if adjacent.is_a?(self.class) && (adjacent.id != id)
50
- adjacent.update!(priority: priority)
51
- end
52
- update(priority: new_priority)
53
-
54
- self.class.siblings(self).map { |e| [e.id, e.priority] }.to_h
55
- end
56
-
57
- private
58
-
59
- def set_next_priority
60
- if id.nil? && priority == 1
61
- self.priority = self.class.siblings(self).maximum(:priority).to_i + 1
62
- end
63
- end
64
-
65
- def normalize_priority
66
- self.priority = PRIORITY_RANGE.first if priority < PRIORITY_RANGE.first
67
- self.priority = PRIORITY_RANGE.last if priority > PRIORITY_RANGE.last
61
+ poll_answers.pluck(:poll_votes_count).sum
68
62
  end
69
63
  end
@@ -1,10 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # User allowed to vote in poll
4
+ #
5
+ # Attributes:
6
+ # created_at [DateTime]
7
+ # poll_id [Poll]
8
+ # user_id [User]
9
+ # updated_at [DateTime]
1
10
  class PollUser < ApplicationRecord
2
11
  include HasOwner
3
12
 
4
13
  belongs_to :poll
5
14
  belongs_to :user
6
15
 
7
- validates_uniqueness_of :user_id, scope: [:poll_id]
16
+ validates_uniqueness_of :user_id, scope: :poll_id
8
17
 
9
18
  scope :list_for_administration, -> { order('id desc') }
10
19
  end
@@ -1,21 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Vote for poll answer
4
+ #
5
+ # Attributes:
6
+ # agent_id [Agent], optional
7
+ # created_at [DateTime]
8
+ # data [jsonb]
9
+ # ip [inet], optional
10
+ # poll_answer_id [PollAnswer]
11
+ # slug [string]
12
+ # updated_at [DateTime]
13
+ # user_id [User], optional
14
+ # uuid [uuid]
1
15
  class PollVote < ApplicationRecord
2
- PER_PAGE = 20
16
+ include HasOwner
17
+ include HasUuid
3
18
 
4
19
  belongs_to :poll_answer, counter_cache: true
5
20
  belongs_to :user
6
21
  belongs_to :agent, optional: true
7
22
 
8
- before_save { self.footprint = "#{user_id}:#{ip}:#{agent_id}" }
9
-
10
23
  scope :recent, -> { order('id desc') }
24
+ scope :list_for_visitors, -> { recent }
25
+ scope :list_for_administration, -> { recent }
11
26
 
12
27
  # @param [Integer] page
13
28
  def self.page_for_administration(page = 1)
14
- recent.page(page).per(PER_PAGE)
29
+ list_for_administration.page(page)
15
30
  end
16
31
 
17
32
  # @param [Integer] page
18
33
  def self.page_for_visitors(page = 1)
19
- recent.page(page).per(PER_PAGE)
34
+ list_for_visitors.page(page)
20
35
  end
21
36
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Biovision
4
+ module Components
5
+ # Managing polls
6
+ class PollsComponent < BaseComponent
7
+
8
+ protected
9
+
10
+ # @param [Hash] data
11
+ # @return [Hash]
12
+ def normalize_settings(data)
13
+ result = {}
14
+ numbers = %w[answer_limit question_limit]
15
+ numbers.each { |f| result[f] = data[f].to_i }
16
+
17
+ result
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1 @@
1
+ <li><%= render 'admin/polls/nav_item' %></li>
@@ -1,6 +1,3 @@
1
- <div class="image">
2
- <%= poll_image_preview(entity) %>
3
- </div>
4
1
  <div class="data">
5
2
  <div><%= admin_poll_answer_link(entity) %></div>
6
3
  <div class="secondary info">
@@ -1,9 +1,10 @@
1
1
  <% content_for :meta_title, t('.title', poll: @entity.poll.name, answer: @entity.poll_question.text, question: @entity.text) %>
2
2
  <% content_for :breadcrumbs do %>
3
- <%= link_to(t('admin.polls.nav_item.text'), admin_polls_path) %>
4
- <%= admin_poll_link(@entity.poll) %>
5
- <%= admin_poll_question_link(@entity.poll_question) %>
6
- <span><%= @entity.priority %>: <%= @entity.text %></span>
3
+ <%= admin_biovision_component_link(component_handler.component) %>
4
+ <%= link_to(t('admin.polls.index.nav_text'), admin_polls_path) %>
5
+ <%= admin_poll_link(@entity.poll) %>
6
+ <%= admin_poll_question_link(@entity.poll_question) %>
7
+ <span><%= @entity.priority %>: <%= @entity.text %></span>
7
8
  <% end %>
8
9
 
9
10
  <article>
@@ -14,40 +15,29 @@
14
15
  <li><%= edit_icon(edit_poll_answer_path(id: @entity.id)) %></li>
15
16
  </ul>
16
17
 
17
- <% unless @entity.image.blank? %>
18
- <figure>
19
- <%= poll_image_medium(@entity) %>
20
- <figcaption><%= t('activerecord.attributes.poll_answer.image') %></figcaption>
21
- </figure>
22
- <% end %>
23
-
24
18
  <dl>
25
- <dt><%= t(:created_at) %></dt>
26
- <dd>
27
- <%= time_tag(@entity.created_at) %>
28
- </dd>
29
-
30
- <dt><%= t(:updated_at) %></dt>
31
- <dd>
32
- <%= time_tag(@entity.updated_at) %>
33
- </dd>
34
-
35
- <dt><%= t('activerecord.attributes.poll_answer.priority') %></dt>
36
- <dd>
37
- <%= @entity.priority %>
38
- </dd>
39
-
40
- <dt><%= t('activerecord.attributes.poll_answer.poll_question_id') %></dt>
41
- <dd>
42
- <%= admin_poll_question_link(@entity.poll_question) %>
43
- </dd>
44
-
45
- <dt><%= t('activerecord.attributes.poll_answer.text') %></dt>
46
- <dd>
47
- <%= @entity.text %>
48
- </dd>
19
+ <div>
20
+ <dt><%= t('activerecord.attributes.poll_answer.poll_question_id') %></dt>
21
+ <dd>
22
+ <%= admin_poll_question_link(@entity.poll_question) %>
23
+ </dd>
24
+ </div>
25
+
26
+ <%= render partial: 'shared/entity/priority', locals: { entity: @entity } %>
27
+
28
+ <div>
29
+ <dt><%= t('activerecord.attributes.poll_answer.text') %></dt>
30
+ <dd>
31
+ <div class="text"><%= @entity.text %></div>
32
+ </dd>
33
+ </div>
34
+
35
+ <%= render partial: 'shared/entity/uuid', locals: { entity: @entity } %>
36
+ <%= render partial: 'shared/entity/timestamps', locals: { entity: @entity } %>
49
37
  </dl>
50
38
 
39
+ <%= render partial: 'admin/poll_answers/entity/data', locals: { entity: @entity } %>
40
+
51
41
  <section>
52
42
  <h2><%= t(:poll_vote_count, count: @entity.poll_votes_count) %></h2>
53
43
 
@@ -1,6 +1,3 @@
1
- <div class="image">
2
- <%= poll_image_preview(entity) %>
3
- </div>
4
1
  <div class="data">
5
2
  <div><%= admin_poll_question_link(entity) %></div>
6
3
  <% unless entity.comment.blank? %>
@@ -9,11 +6,15 @@
9
6
  </div>
10
7
  <% end %>
11
8
  <div class="secondary info">
12
- <%= t(:poll_answer_count, count: entity.poll_answers_count) %>
9
+ <%= t(:poll_answer_count, count: entity.poll_answers_count) %>,
10
+ <%= t(:poll_vote_count, count: entity.vote_count) %>
13
11
  <% if entity.poll_answers.any? %>
14
12
  <ol>
15
13
  <% entity.poll_answers.ordered_by_priority.each do |answer| %>
16
- <li><%= admin_poll_answer_link(answer) %></li>
14
+ <li>
15
+ <%= admin_poll_answer_link(answer) %>:
16
+ <%= answer.poll_votes_count %> (<%= answer.vote_percent %>%)
17
+ </li>
17
18
  <% end %>
18
19
  </ol>
19
20
  <% end %>
@@ -1,8 +1,9 @@
1
1
  <% content_for :meta_title, t('.title', poll: @entity.poll.name, question: @entity.text) %>
2
2
  <% content_for :breadcrumbs do %>
3
- <%= link_to(t('admin.polls.nav_item.text'), admin_polls_path) %>
4
- <%= admin_poll_link(@entity.poll) %>
5
- <span><%= @entity.priority %>: <%= @entity.text %></span>
3
+ <%= admin_biovision_component_link(component_handler.component) %>
4
+ <%= link_to(t('admin.polls.index.nav_text'), admin_polls_path) %>
5
+ <%= admin_poll_link(@entity.poll) %>
6
+ <span><%= @entity.priority %>: <%= @entity.text %></span>
6
7
  <% end %>
7
8
 
8
9
  <article>
@@ -13,47 +14,38 @@
13
14
  <li><%= edit_icon(edit_poll_question_path(id: @entity.id)) %></li>
14
15
  </ul>
15
16
 
16
- <% unless @entity.image.blank? %>
17
- <figure>
18
- <%= poll_image_medium(@entity) %>
19
- <figcaption><%= t('activerecord.attributes.poll_question.image') %></figcaption>
20
- </figure>
21
- <% end %>
22
-
23
17
  <dl>
24
- <dt><%= t(:created_at) %></dt>
25
- <dd>
26
- <%= time_tag(@entity.created_at) %>
27
- </dd>
28
-
29
- <dt><%= t(:updated_at) %></dt>
30
- <dd>
31
- <%= time_tag(@entity.updated_at) %>
32
- </dd>
18
+ <div>
19
+ <dt><%= t('attributes.poll') %></dt>
20
+ <dd>
21
+ <%= admin_poll_link(@entity.poll) %>
22
+ </dd>
23
+ </div>
33
24
 
34
- <dt><%= t('activerecord.attributes.poll_question.poll_id') %></dt>
35
- <dd>
36
- <%= admin_poll_link(@entity.poll) %>
37
- </dd>
25
+ <%= render partial: 'shared/entity/priority', locals: { entity: @entity } %>
38
26
 
39
- <dt><%= t('activerecord.attributes.poll_question.priority') %></dt>
40
- <dd>
41
- <%= @entity.priority %>
42
- </dd>
43
-
44
- <dt><%= t('activerecord.attributes.poll_question.text') %></dt>
45
- <dd>
46
- <%= @entity.text %>
47
- </dd>
27
+ <div>
28
+ <dt><%= t('activerecord.attributes.poll_question.text') %></dt>
29
+ <dd>
30
+ <div class="text"><%= @entity.text %></div>
31
+ </dd>
32
+ </div>
48
33
 
49
34
  <% unless @entity.comment.blank? %>
35
+ <div>
50
36
  <dt><%= t('activerecord.attributes.poll_question.comment') %></dt>
51
37
  <dd>
52
- <%= @entity.comment %>
38
+ <div class="text"><%= @entity.comment %></div>
53
39
  </dd>
40
+ </div>
54
41
  <% end %>
42
+
43
+ <%= render partial: 'shared/entity/uuid', locals: { entity: @entity } %>
44
+ <%= render partial: 'shared/entity/timestamps', locals: { entity: @entity } %>
55
45
  </dl>
56
46
 
47
+ <%= render partial: 'admin/poll_questions/entity/data', locals: { entity: @entity } %>
48
+
57
49
  <%=
58
50
  render(
59
51
  partial: 'shared/admin/toggleable',
@@ -76,10 +68,10 @@
76
68
  </section>
77
69
 
78
70
  <% if @entity.poll_answers.count < 10 %>
79
- <section>
80
- <h2><%= t('poll_answers.new.heading') %></h2>
71
+ <section>
72
+ <h2><%= t('poll_answers.new.heading') %></h2>
81
73
 
82
- <%= render partial: 'poll_answers/form', locals: { entity: @entity.poll_answers.new } %>
83
- </section>
74
+ <%= render partial: 'poll_answers/form', locals: { entity: @entity.poll_answers.new } %>
75
+ </section>
84
76
  <% end %>
85
77
  </article>