effective_polls 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/admin/polls_controller.rb +1 -7
- data/app/controllers/effective/ballots_controller.rb +4 -1
- data/app/datatables/admin/effective_poll_notifications_datatable.rb +4 -1
- data/app/datatables/admin/effective_poll_results_datatable.rb +1 -4
- data/app/datatables/admin/effective_polls_datatable.rb +1 -0
- data/app/datatables/{effective_polls_datatable.rb → effective_polls_available_polls_datatable.rb} +6 -4
- data/app/helpers/effective_polls_helper.rb +17 -13
- data/app/mailers/effective/polls_mailer.rb +3 -1
- data/app/models/concerns/effective_polls_user.rb +67 -0
- data/app/models/effective/ballot.rb +11 -2
- data/app/models/effective/ballot_response.rb +1 -1
- data/app/models/effective/poll.rb +39 -26
- data/app/models/effective/poll_notification.rb +2 -2
- data/app/models/effective/poll_question.rb +1 -1
- data/app/models/effective/poll_question_option.rb +1 -1
- data/app/views/admin/poll_notifications/_form.html.haml +3 -5
- data/app/views/admin/poll_questions/_form.html.haml +12 -5
- data/app/views/admin/polls/_form.html.haml +10 -5
- data/app/views/admin/polls/_form_content.html.haml +16 -20
- data/app/views/admin/polls/_form_poll.html.haml +16 -7
- data/app/views/admin/polls/_poll.html.haml +5 -0
- data/app/views/effective/ballots/_content.html.haml +10 -0
- data/app/views/effective/ballots/_layout.html.haml +3 -0
- data/app/views/effective/ballots/complete.html.haml +13 -8
- data/app/views/effective/ballots/start.html.haml +29 -12
- data/app/views/effective/ballots/submit.html.haml +10 -13
- data/app/views/effective/ballots/vote.html.haml +10 -15
- data/app/views/effective/poll_results/_results.html.haml +2 -2
- data/app/views/effective/polls/_dashboard.html.haml +25 -0
- data/app/views/effective/polls_mailer/poll_before_poll_ends.liquid +0 -1
- data/app/views/effective/polls_mailer/poll_reminder.liquid +0 -1
- data/app/views/effective/polls_mailer/poll_upcoming_reminder.liquid +0 -1
- data/app/views/effective/polls_mailer/poll_when_poll_ends.liquid +0 -1
- data/app/views/effective/polls_mailer/poll_when_poll_starts.liquid +0 -1
- data/config/effective_polls.rb +2 -11
- data/config/locales/effective_polls.yml +14 -0
- data/config/routes.rb +2 -5
- data/db/migrate/101_create_effective_polls.rb +12 -10
- data/db/seeds.rb +2 -1
- data/lib/effective_polls/engine.rb +7 -0
- data/lib/effective_polls/version.rb +1 -1
- data/lib/effective_polls.rb +2 -4
- data/lib/tasks/effective_polls_tasks.rake +23 -12
- metadata +9 -4
- data/app/views/admin/polls/results.html.haml +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 637320f25a72489ada773806629e70590bb5c8435e871a6de40497e2eb6300ed
|
4
|
+
data.tar.gz: e797d1afdad6be66099b291ec7a809cbb65ef32d7963ca04f03d3ac3d91fe2a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7317013d4063bdd11eaf4a72b6d5ca964c7acb2c35ac29653e9c7043c4e4c40de4e1b4b55079ed023b758f08982a51ca17926e37c5abafbca2462cf0b4a9e657
|
7
|
+
data.tar.gz: d3fe9a3b04a9ca98c5a27fa956fb82d536db6b9662b6d61a0e8fd954f603673384f6d70c3ec33e51fabde548063b126892508e858be72e616d2c9ff30318e732
|
@@ -5,13 +5,7 @@ module Admin
|
|
5
5
|
|
6
6
|
include Effective::CrudController
|
7
7
|
|
8
|
-
|
9
|
-
@poll = Effective::Poll.find(params[:id])
|
10
|
-
EffectiveResources.authorize!(self, :results, @poll)
|
11
|
-
|
12
|
-
@datatable = Admin::EffectivePollResultsDatatable.new(poll_token: @poll.token)
|
13
|
-
@page_title = "#{@poll} Results"
|
14
|
-
end
|
8
|
+
on :save, only: :create, redirect: :edit
|
15
9
|
|
16
10
|
def permitted_params
|
17
11
|
params.require(:effective_poll).permit!
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Effective
|
2
2
|
class BallotsController < ApplicationController
|
3
|
-
|
3
|
+
|
4
|
+
if defined?(Devise)
|
5
|
+
before_action :authenticate_user!, unless: -> { action_name == 'new' || (action_name == 'show' && params[:id] == 'start') }
|
6
|
+
end
|
4
7
|
|
5
8
|
include Effective::WizardController
|
6
9
|
|
@@ -41,10 +41,7 @@ class Admin::EffectivePollResultsDatatable < Effective::Datatable
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def poll
|
44
|
-
@poll ||=
|
45
|
-
raise('expected datatable poll_token attribute') unless attributes[:poll_token]
|
46
|
-
Effective::Poll.deep_results.find(attributes[:poll_token])
|
47
|
-
end
|
44
|
+
@poll ||= Effective::Poll.deep_results.where(id: attributes[:poll_id]).first!
|
48
45
|
end
|
49
46
|
|
50
47
|
end
|
data/app/datatables/{effective_polls_datatable.rb → effective_polls_available_polls_datatable.rb}
RENAMED
@@ -1,13 +1,14 @@
|
|
1
|
+
# Dashboard available polls
|
1
2
|
# Displays available polls that the current_user may complete
|
2
3
|
|
3
|
-
class
|
4
|
+
class EffectivePollsAvailablePollsDatatable < Effective::Datatable
|
4
5
|
datatable do
|
5
6
|
order :start_at
|
6
7
|
|
7
8
|
col :start_at, visible: false
|
8
9
|
|
9
10
|
col :title
|
10
|
-
col :available_date
|
11
|
+
col :available_date
|
11
12
|
|
12
13
|
actions_col(actions: []) do |poll|
|
13
14
|
ballot = poll.ballots.where(user: current_user).first
|
@@ -15,16 +16,17 @@ class EffectivePollsDatatable < Effective::Datatable
|
|
15
16
|
if ballot.blank?
|
16
17
|
dropdown_link_to('Start', effective_polls.poll_ballot_build_path(poll, :new, :start))
|
17
18
|
elsif ballot.completed?
|
19
|
+
#dropdown_link_to('Show', effective_polls.poll_ballot_path(poll, ballot))
|
18
20
|
'Complete'
|
19
21
|
else
|
20
22
|
dropdown_link_to('Continue', effective_polls.poll_ballot_build_path(poll, ballot, ballot.next_step))
|
23
|
+
dropdown_link_to('Delete', effective_polls.poll_ballot_path(poll, ballot), 'data-confirm': "Really delete #{ballot}?", 'data-method': :delete)
|
21
24
|
end
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
25
28
|
collection do
|
26
|
-
|
27
|
-
Effective::Poll.available.select { |poll| poll.available_for?(current_user) }
|
29
|
+
Effective::Poll.where(id: current_user.available_polls)
|
28
30
|
end
|
29
31
|
|
30
32
|
end
|
@@ -1,22 +1,26 @@
|
|
1
1
|
module EffectivePollsHelper
|
2
2
|
|
3
|
+
# Used on dashboard
|
4
|
+
def polls_name_label
|
5
|
+
et('effective_polls.name')
|
6
|
+
end
|
7
|
+
|
3
8
|
# Used by admin/polls form
|
4
|
-
def effective_polls_audience_scope_collection
|
5
|
-
|
6
|
-
|
7
|
-
(key.present? && value.present?) ? [key, value] : [key.to_s.titleize, key]
|
8
|
-
end
|
9
|
+
def effective_polls_audience_scope_collection(poll)
|
10
|
+
klass = poll.try(:audience_class)
|
11
|
+
raise('expected a poll with an audience_class') unless klass.try(:effective_polls_user?)
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
13
|
+
resource = klass.new
|
14
|
+
|
15
|
+
scopes = resource.poll_audience_scopes
|
16
|
+
raise('expected poll audience scopes') unless scopes.kind_of?(Array)
|
16
17
|
|
17
18
|
# Append the number of users in this scope
|
18
|
-
scopes.map
|
19
|
-
|
19
|
+
scopes.map do |label, scope|
|
20
|
+
relation = resource.poll_audience_scope(scope)
|
21
|
+
raise("invalid poll_audience_scope for #{scope}") unless relation.kind_of?(ActiveRecord::Relation)
|
22
|
+
|
23
|
+
["#{label} (#{pluralize(relation.count, 'user')})", scope]
|
20
24
|
end
|
21
25
|
end
|
22
26
|
|
@@ -75,7 +75,9 @@ module Effective
|
|
75
75
|
title: poll.title,
|
76
76
|
url: effective_polls.poll_url(poll),
|
77
77
|
user: {
|
78
|
-
name: user.to_s,
|
78
|
+
name: (user.try(:email_to_s) || user.to_s),
|
79
|
+
first_name: user.try(:first_name).to_s,
|
80
|
+
last_name: user.try(:last_name).to_s,
|
79
81
|
email: user.email
|
80
82
|
}
|
81
83
|
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# EffectivePollsUser
|
2
|
+
#
|
3
|
+
# Mark your user model with effective_polls_user to get all the includes
|
4
|
+
|
5
|
+
module EffectivePollsUser
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module Base
|
9
|
+
def effective_polls_user
|
10
|
+
include ::EffectivePollsUser
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def effective_polls_user?; true; end
|
16
|
+
end
|
17
|
+
|
18
|
+
included do
|
19
|
+
has_many :ballots, -> { Effective::Ballot.sorted }, inverse_of: :user, as: :user, class_name: 'Effective::Ballot'
|
20
|
+
end
|
21
|
+
|
22
|
+
# The list of all available audience scopes for the Poll Selected Users
|
23
|
+
def poll_audience_scopes
|
24
|
+
scopes = [
|
25
|
+
['All Users', :all]
|
26
|
+
]
|
27
|
+
|
28
|
+
if self.class.try(:effective_memberships_user?)
|
29
|
+
scopes += [
|
30
|
+
['All members', :members],
|
31
|
+
['All removed members', :membership_removed],
|
32
|
+
['All members in good standing', :membership_in_good_standing],
|
33
|
+
['All members not in good standing', :membership_not_in_good_standing],
|
34
|
+
['All members renewed this period', :membership_renewed_this_period],
|
35
|
+
]
|
36
|
+
|
37
|
+
scopes += EffectiveMemberships.Category.sorted.map do |category|
|
38
|
+
["All #{category} members", "members_with_category_id_#{category.id}"]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
scopes
|
43
|
+
end
|
44
|
+
|
45
|
+
# Turns the given audience_scope value into the actual ActiveRecord::Relation scope
|
46
|
+
def poll_audience_scope(value)
|
47
|
+
collection = self.class.respond_to?(:unarchived) ? self.class.unarchived : self.class
|
48
|
+
|
49
|
+
# If we respond to the fill value, call it
|
50
|
+
return collection.send(value) if collection.respond_to?(value)
|
51
|
+
|
52
|
+
# Parse the value
|
53
|
+
name, id = value.to_s.split('_id_')
|
54
|
+
|
55
|
+
case name.try(:to_sym)
|
56
|
+
when :members_with_category
|
57
|
+
collection.members_with_category(EffectiveMemberships.Category.find(id))
|
58
|
+
else
|
59
|
+
raise("unknown poll_audience_scope for #{value}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def available_polls
|
64
|
+
Effective::Poll.available.select { |poll| poll.available_for?(self) }
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -3,14 +3,19 @@ module Effective
|
|
3
3
|
attr_accessor :current_user
|
4
4
|
attr_accessor :current_step
|
5
5
|
|
6
|
+
# Application namespace
|
7
|
+
belongs_to :user, polymorphic: true
|
8
|
+
|
9
|
+
# Effective namespace
|
6
10
|
belongs_to :poll
|
7
|
-
belongs_to :user
|
8
11
|
|
9
12
|
has_many :ballot_responses, dependent: :destroy
|
10
13
|
accepts_nested_attributes_for :ballot_responses
|
11
14
|
|
12
15
|
acts_as_tokened
|
13
16
|
|
17
|
+
log_changes(to: :poll) if respond_to?(:log_changes)
|
18
|
+
|
14
19
|
acts_as_wizard(
|
15
20
|
start: 'Start',
|
16
21
|
vote: 'Ballot',
|
@@ -34,6 +39,10 @@ module Effective
|
|
34
39
|
|
35
40
|
scope :deep, -> { includes(:poll, :user, ballot_responses: [:poll, :poll_question, :poll_question_options]) }
|
36
41
|
scope :sorted, -> { order(:id) }
|
42
|
+
|
43
|
+
scope :in_progress, -> { where(completed_at: nil) }
|
44
|
+
scope :done, -> { where.not(completed_at: nil) }
|
45
|
+
|
37
46
|
scope :completed, -> { where.not(completed_at: nil) }
|
38
47
|
|
39
48
|
before_validation(if: -> { new_record? }) do
|
@@ -48,7 +57,7 @@ module Effective
|
|
48
57
|
validates :ballot_responses, associated: true
|
49
58
|
|
50
59
|
def to_s
|
51
|
-
|
60
|
+
model_name.human
|
52
61
|
end
|
53
62
|
|
54
63
|
# Find or build
|
@@ -1,10 +1,6 @@
|
|
1
1
|
module Effective
|
2
2
|
class Poll < ActiveRecord::Base
|
3
|
-
|
4
|
-
has_rich_text :start_content
|
5
|
-
has_rich_text :vote_content
|
6
|
-
has_rich_text :submit_content
|
7
|
-
has_rich_text :complete_content
|
3
|
+
acts_as_tokened
|
8
4
|
|
9
5
|
has_many :poll_notifications, -> { order(:id) }, inverse_of: :poll, dependent: :destroy
|
10
6
|
accepts_nested_attributes_for :poll_notifications, allow_destroy: true
|
@@ -19,7 +15,12 @@ module Effective
|
|
19
15
|
has_many :completed_ballots, -> { Effective::Ballot.completed }, class_name: 'Effective::Ballot'
|
20
16
|
has_many :completed_ballot_responses, -> { where(ballot: Effective::Ballot.completed) }, class_name: 'Effective::BallotResponse'
|
21
17
|
|
22
|
-
|
18
|
+
has_many_rich_texts
|
19
|
+
# rich_text_all_steps_content
|
20
|
+
# rich_text_start_content
|
21
|
+
# rich_text_vote_content
|
22
|
+
# rich_text_submit_content
|
23
|
+
# rich_text_complete_content
|
23
24
|
|
24
25
|
if respond_to?(:log_changes)
|
25
26
|
log_changes(except: [:ballots, :ballot_responses, :completed_ballots, :completed_ballot_responses])
|
@@ -29,29 +30,23 @@ module Effective
|
|
29
30
|
|
30
31
|
effective_resource do
|
31
32
|
# Acts as tokened
|
32
|
-
token
|
33
|
+
token :string, permitted: false
|
33
34
|
|
34
35
|
title :string
|
35
36
|
|
36
37
|
start_at :datetime
|
37
38
|
end_at :datetime
|
38
39
|
|
39
|
-
audience
|
40
|
-
|
40
|
+
audience :string
|
41
|
+
audience_class_name :string
|
42
|
+
audience_scope :text # An Array of user_ids or named scopes on the User model
|
41
43
|
|
42
44
|
timestamps
|
43
45
|
end
|
44
46
|
|
45
47
|
serialize :audience_scope, Array
|
46
48
|
|
47
|
-
scope :deep, -> {
|
48
|
-
includes(poll_questions: :poll_question_options)
|
49
|
-
.with_rich_text_all_steps_content
|
50
|
-
.with_rich_text_start_content
|
51
|
-
.with_rich_text_vote_content
|
52
|
-
.with_rich_text_submit_content
|
53
|
-
.with_rich_text_complete_content
|
54
|
-
}
|
49
|
+
scope :deep, -> { includes(poll_questions: :poll_question_options) }
|
55
50
|
|
56
51
|
scope :deep_results, -> {
|
57
52
|
includes(poll_questions: :poll_question_options)
|
@@ -68,6 +63,8 @@ module Effective
|
|
68
63
|
validates :start_at, presence: true
|
69
64
|
|
70
65
|
validates :audience, inclusion: { in: AUDIENCES }
|
66
|
+
validates :audience_class_name, presence: true
|
67
|
+
|
71
68
|
validates :audience_scope, presence: true, unless: -> { audience == 'All Users' }
|
72
69
|
|
73
70
|
validate(if: -> { start_at.present? && end_at.present? }) do
|
@@ -75,33 +72,49 @@ module Effective
|
|
75
72
|
end
|
76
73
|
|
77
74
|
def to_s
|
78
|
-
title.presence ||
|
75
|
+
title.presence || model_name.human
|
79
76
|
end
|
80
77
|
|
81
78
|
def available_for?(user)
|
82
|
-
raise('expected
|
79
|
+
raise('expected an effective_polls_user') unless user.class.try(:effective_polls_user?)
|
83
80
|
available? && users.include?(user)
|
84
81
|
end
|
85
82
|
|
83
|
+
def audience_class
|
84
|
+
klass = audience_class_name.safe_constantize
|
85
|
+
raise('expected an effective_polls_user klass') unless klass.try(:effective_polls_user?)
|
86
|
+
klass
|
87
|
+
end
|
88
|
+
|
86
89
|
def users(except_completed: false)
|
90
|
+
klass = audience_class()
|
91
|
+
resource = klass.new
|
92
|
+
|
87
93
|
users = case audience
|
88
94
|
when 'All Users'
|
89
|
-
|
95
|
+
klass.try(:unarchived) || klass.all
|
90
96
|
when 'Individual Users'
|
91
|
-
|
97
|
+
(klass.try(:unarchived) || klass.all).where(id: audience_scope)
|
92
98
|
when 'Selected Users'
|
93
|
-
collection =
|
94
|
-
|
99
|
+
collection = klass.none
|
100
|
+
|
101
|
+
audience_scope.each do |scope|
|
102
|
+
relation = resource.poll_audience_scope(scope)
|
103
|
+
raise("invalid poll_audience_scope for #{scope}") unless relation.kind_of?(ActiveRecord::Relation)
|
104
|
+
|
105
|
+
collection = collection.or(relation)
|
106
|
+
end
|
107
|
+
|
95
108
|
collection
|
96
109
|
else
|
97
110
|
raise('unexpected audience')
|
98
111
|
end
|
99
112
|
|
100
113
|
if except_completed
|
101
|
-
users.where.not(id: completed_ballots.select('user_id as id'))
|
102
|
-
else
|
103
|
-
users
|
114
|
+
users = users.where.not(id: completed_ballots.select('user_id as id'))
|
104
115
|
end
|
116
|
+
|
117
|
+
users
|
105
118
|
end
|
106
119
|
|
107
120
|
def available?
|
@@ -72,7 +72,7 @@ module Effective
|
|
72
72
|
validates :subject, presence: true
|
73
73
|
validates :body, presence: true
|
74
74
|
|
75
|
-
if EffectivePolls.use_effective_email_templates
|
75
|
+
with_options(if: -> { EffectivePolls.use_effective_email_templates }) do
|
76
76
|
validates :body, liquid: true
|
77
77
|
validates :subject, liquid: true
|
78
78
|
end
|
@@ -81,7 +81,7 @@ module Effective
|
|
81
81
|
presence: true, uniqueness: { scope: [:poll_id, :category], message: 'already exists' }
|
82
82
|
|
83
83
|
def to_s
|
84
|
-
'
|
84
|
+
[category.presence, subject.presence].compact.join(' - ') || model_name.human
|
85
85
|
end
|
86
86
|
|
87
87
|
def email_template
|
@@ -12,22 +12,20 @@
|
|
12
12
|
- template = 'poll_' + category.parameterize.underscore
|
13
13
|
|
14
14
|
= f.show_if :category, category do
|
15
|
-
= render "/admin/poll_notifications/form_#{template}", f: f
|
15
|
+
.my-3= render "/admin/poll_notifications/form_#{template}", f: f
|
16
|
+
|
17
|
+
= f.select :from, EffectivePolls.mailer_froms
|
16
18
|
|
17
19
|
- if f.object.category == category
|
18
|
-
= f.email_field :from
|
19
20
|
= f.text_field :subject
|
20
21
|
= f.text_area :body, rows: 10
|
21
22
|
|
22
23
|
- elsif EffectivePolls.use_effective_email_templates == false
|
23
|
-
= f.email_field :from, value: EffectivePolls.mailer[:default_from]
|
24
24
|
= f.text_field :subject, value: ''
|
25
25
|
= f.text_area :body, rows: 10, value: ''
|
26
26
|
|
27
27
|
- else
|
28
28
|
- email_template = Effective::EmailTemplate.where(template_name: template).first!
|
29
|
-
|
30
|
-
= f.email_field :from, value: email_template.from
|
31
29
|
= f.text_field :subject, value: email_template.subject
|
32
30
|
= f.text_area :body, rows: 10, value: email_template.body
|
33
31
|
|
@@ -2,19 +2,26 @@
|
|
2
2
|
- if inline_datatable?
|
3
3
|
= f.hidden_field :poll_id
|
4
4
|
- else
|
5
|
-
= f.select :poll_id, Effective::Poll.
|
5
|
+
= f.select :poll_id, Effective::Poll.all
|
6
6
|
|
7
7
|
= f.text_field :title, label: 'Question Title'
|
8
|
-
|
8
|
+
|
9
|
+
- if defined?(EffectiveArticleEditor)
|
10
|
+
= f.article_editor :body, label: 'Body (optional)'
|
11
|
+
- else
|
12
|
+
= f.rich_text_area :body, label: 'Body (optional)'
|
9
13
|
|
10
14
|
= f.check_box :required, hint: 'A response to this question will be required'
|
11
15
|
= f.select :category, Effective::PollQuestion::CATEGORIES
|
12
16
|
|
13
17
|
= f.show_if :category, 'Choose one' do
|
14
|
-
.card
|
18
|
+
.mt-3.card
|
15
19
|
.card-body
|
16
|
-
%h5
|
17
|
-
%p Display
|
20
|
+
%h5 Options
|
21
|
+
%p Display the following options:
|
22
|
+
|
23
|
+
= f.has_many :poll_question_options, build: true do |fa|
|
24
|
+
= fa.text_field :title, label: false
|
18
25
|
|
19
26
|
= f.show_if :category, 'Select all that apply' do
|
20
27
|
.card
|
@@ -7,18 +7,23 @@
|
|
7
7
|
= render 'admin/polls/form_content', poll: poll
|
8
8
|
|
9
9
|
= tab 'Questions' do
|
10
|
-
- datatable = Admin::EffectivePollQuestionsDatatable.new(
|
10
|
+
- datatable = Admin::EffectivePollQuestionsDatatable.new(poll: poll)
|
11
11
|
= render_datatable(datatable, inline: true, simple: true)
|
12
12
|
|
13
13
|
= tab 'Notifications' do
|
14
14
|
%p
|
15
15
|
The following email notifications will be sent to
|
16
|
-
= pluralize(poll.users.count, '
|
16
|
+
= pluralize(poll.users.count, 'user')
|
17
17
|
in the audience.
|
18
18
|
|
19
|
-
|
19
|
+
%p
|
20
|
+
The url for this #{et(poll)} is:
|
21
|
+
- url = effective_polls.poll_url(poll)
|
22
|
+
= link_to(url, url, target: '_blank')
|
23
|
+
|
24
|
+
- datatable = Admin::EffectivePollNotificationsDatatable.new(poll: poll)
|
20
25
|
= render_datatable(datatable, inline: true, simple: true)
|
21
26
|
|
22
|
-
- if poll.respond_to?(:
|
27
|
+
- if poll.respond_to?(:logs_datatable)
|
23
28
|
= tab 'Logs' do
|
24
|
-
= render_datatable(poll.
|
29
|
+
= render_datatable(poll.logs_datatable)
|
@@ -1,27 +1,23 @@
|
|
1
|
+
%p Each of the following content areas will be displayed on the ballot wizard.
|
2
|
+
|
1
3
|
= effective_form_with(model: [:admin, poll], engine: true) do |f|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
= card("All Steps") do
|
5
|
+
- if defined?(EffectiveArticleEditor)
|
6
|
+
= f.article_editor "rich_text_all_steps_content", label: false, hint: "displayed on all steps"
|
7
|
+
- else
|
8
|
+
= f.rich_text_area "rich_text_all_steps_content", label: false, hint: "displayed on all steps"
|
6
9
|
|
7
|
-
|
8
|
-
.card-body
|
9
|
-
%h5.card-title Start Step
|
10
|
-
= f.rich_text_area :start_content, label: false, hint: 'displayed on the start step only'
|
10
|
+
%hr
|
11
11
|
|
12
|
-
.
|
13
|
-
.card-body
|
14
|
-
%h5.card-title Vote Step
|
15
|
-
= f.rich_text_area :vote_content, label: false, hint: 'displayed on the vote step only'
|
12
|
+
- enabled = Effective::Ballot.all_wizard_steps
|
16
13
|
|
17
|
-
.
|
18
|
-
.
|
19
|
-
%h5.card-title Review and Submit Step
|
20
|
-
= f.rich_text_area :submit_content, label: false, hint: 'displayed on the review and submit step only'
|
14
|
+
- Effective::Ballot::WIZARD_STEPS.each do |step, title|
|
15
|
+
- next unless enabled.include?(step)
|
21
16
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
17
|
+
= card("#{title}") do
|
18
|
+
- if defined?(EffectiveArticleEditor)
|
19
|
+
= f.article_editor "rich_text_#{step}_content", label: false, hint: "displayed on the ballot #{step} wizard step only"
|
20
|
+
- else
|
21
|
+
= f.rich_text_area "rich_text_#{step}_content", label: false, hint: "displayed on the ballot #{step} wizard step only"
|
26
22
|
|
27
23
|
= f.submit
|
@@ -1,32 +1,41 @@
|
|
1
1
|
= effective_form_with(model: [:admin, poll], engine: true) do |f|
|
2
|
+
|
2
3
|
= f.text_field :title, hint: 'The title of your poll or election.'
|
3
4
|
|
4
|
-
= f.datetime_field :start_at
|
5
|
+
= f.datetime_field :start_at
|
5
6
|
= f.datetime_field :end_at
|
6
7
|
|
8
|
+
- if f.object.poll_notifications.present?
|
9
|
+
.alert.alert-info
|
10
|
+
Please be aware of the existing #{ets(f.object.poll_notifications)} when changing the start or end availability date.
|
11
|
+
|
7
12
|
-# Audience
|
13
|
+
- f.object.audience_class_name ||= current_user.class.name
|
14
|
+
|
15
|
+
= f.hidden_field :audience_class_name
|
8
16
|
= f.radios :audience, Effective::Poll::AUDIENCES
|
9
17
|
|
10
18
|
= f.show_if :audience, 'All Users' do
|
11
19
|
.card
|
12
20
|
.card-body
|
13
21
|
%h5 All Users
|
14
|
-
%p All users may complete this poll
|
22
|
+
%p All users may complete this #{etd(poll)}
|
15
23
|
|
16
24
|
= f.show_if :audience, 'Individual Users' do
|
17
25
|
.card
|
18
26
|
.card-body
|
19
27
|
%h5 Individual Users
|
20
|
-
%p Only the following individual users may complete this poll
|
28
|
+
%p Only the following individual users may complete this #{etd(poll)}
|
21
29
|
|
22
|
-
|
23
|
-
|
30
|
+
-# Audience Users
|
31
|
+
- ajax_url = (@select2_users_ajax_path || effective_resources.users_admin_select2_ajax_index_path) unless Rails.env.test?
|
32
|
+
= f.select :audience_scope, current_user.class.all, ajax_url: ajax_url, multiple: true
|
24
33
|
|
25
34
|
= f.show_if :audience, 'Selected Users' do
|
26
35
|
.card
|
27
36
|
.card-body
|
28
37
|
%h5 Selected Users
|
29
|
-
%p Users within any of the following groups may complete this poll
|
30
|
-
= f.checks :audience_scope, effective_polls_audience_scope_collection(), multiple: true, label: false
|
38
|
+
%p Users within any of the following groups may complete this #{etd(poll)}
|
39
|
+
= f.checks :audience_scope, effective_polls_audience_scope_collection(f.object), multiple: true, label: false
|
31
40
|
|
32
41
|
= effective_submit(f)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
- all_steps_content = resource.poll&.rich_text_all_steps_content
|
2
|
+
- step_content = resource.poll&.send("rich_text_#{step}_content")
|
3
|
+
|
4
|
+
- if all_steps_content.present?
|
5
|
+
.card.mb-4
|
6
|
+
.card-body= all_steps_content.to_s
|
7
|
+
|
8
|
+
- if step_content.present?
|
9
|
+
.card.mb-4
|
10
|
+
.card-body= step_content.to_s
|
@@ -1,11 +1,16 @@
|
|
1
|
-
=
|
2
|
-
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/ballots/content', resource: resource
|
3
3
|
|
4
|
-
-
|
5
|
-
.mb-2= resource.poll.all_steps_content
|
4
|
+
- raise('expected a completed? poll') unless resource.completed?
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
.alert.alert-warning.mb-4
|
7
|
+
Successfully completed on #{resource.completed_at.strftime('%F')}.
|
9
8
|
|
10
|
-
.
|
11
|
-
|
9
|
+
.mb-4
|
10
|
+
= link_to "Return to Dashboard", return_to_dashboard_path, class: 'btn btn-lg btn-primary btn-block'
|
11
|
+
|
12
|
+
= card do
|
13
|
+
%p= resource.poll
|
14
|
+
= render 'effective/ballots/ballot', ballot: resource
|
15
|
+
|
16
|
+
= link_to "Return to Dashboard", return_to_dashboard_path, class: 'btn btn-lg btn-primary btn-block'
|
@@ -1,17 +1,34 @@
|
|
1
|
-
=
|
2
|
-
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/ballots/content', resource: resource
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
- # Signed out
|
5
|
+
- if resource.user.blank?
|
6
|
+
= card do
|
7
|
+
%p Welcome!
|
7
8
|
|
8
|
-
|
9
|
-
.mb-2= resource.poll.all_steps_content
|
9
|
+
%p You are about to register for #{resource.poll}.
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
%p
|
12
|
+
Please
|
13
|
+
= link_to 'sign in', '/users/sign_in'
|
14
|
+
or
|
15
|
+
= link_to 'sign up', '/users/sign_up'
|
16
|
+
to continue.
|
17
|
+
|
18
|
+
%p= link_to 'Sign In to Continue', '/users/sign_in', class: 'btn btn-primary'
|
13
19
|
|
14
|
-
|
15
|
-
|
20
|
+
- # Signed in
|
21
|
+
- if resource.user.present?
|
22
|
+
.alert.alert-warning.mb-4
|
23
|
+
This is a <strong>Secret Ballot</strong>.
|
24
|
+
Only you will know what you have submitted and no one has access to individual ballots.
|
16
25
|
|
17
|
-
=
|
26
|
+
= card do
|
27
|
+
%p Welcome #{current_user}!
|
28
|
+
|
29
|
+
%p You are starting a #{etd(resource.poll)} for #{resource.poll}.
|
30
|
+
|
31
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
32
|
+
= f.hidden_field :current_step
|
33
|
+
|
34
|
+
= f.submit 'Start', center: true
|
@@ -1,17 +1,14 @@
|
|
1
|
-
=
|
2
|
-
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/ballots/content', resource: resource
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
= card do
|
5
|
+
%p= resource.poll
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
8
|
+
= f.hidden_field :current_step
|
9
9
|
|
10
|
-
|
11
|
-
= f.hidden_field :current_step
|
10
|
+
= render(resource)
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
= link_to 'Change Ballot', wizard_path(:vote), class: 'btn btn-secondary'
|
17
|
-
= f.save 'Submit Ballot'
|
12
|
+
= f.submit(center: true) do
|
13
|
+
= link_to 'Change Ballot', wizard_path(:vote), class: 'btn btn-secondary'
|
14
|
+
= f.save 'Submit Ballot'
|
@@ -1,19 +1,14 @@
|
|
1
|
-
=
|
2
|
-
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/ballots/content', resource: resource
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
= card do
|
5
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
6
|
+
= f.hidden_field :current_step
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
- resource.poll.poll_questions.deep.all.each_with_index do |poll_question, index|
|
9
|
+
- ballot_response = resource.ballot_response(poll_question)
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
= f.fields_for :ballot_responses, ballot_response do |fbr|
|
12
|
+
= render('/effective/ballot_responses/fields', f: fbr, poll_question: poll_question)
|
12
13
|
|
13
|
-
|
14
|
-
- ballot_response = resource.ballot_response(poll_question)
|
15
|
-
|
16
|
-
= f.fields_for :ballot_responses, ballot_response do |fbr|
|
17
|
-
= render('/effective/ballot_responses/fields', f: fbr, poll_question: poll_question)
|
18
|
-
|
19
|
-
= f.submit 'Save and Continue', center: true
|
14
|
+
= f.submit 'Save and Continue', center: true
|
@@ -6,11 +6,11 @@
|
|
6
6
|
|
7
7
|
%p
|
8
8
|
%strong
|
9
|
-
= pluralize(poll.completed_ballots.count, '
|
9
|
+
= pluralize(poll.completed_ballots.count, 'user')
|
10
10
|
completed
|
11
11
|
ballots from an audience of
|
12
12
|
= succeed('.') do
|
13
|
-
%strong= pluralize(poll.users.count, 'total
|
13
|
+
%strong= pluralize(poll.users.count, 'total user')
|
14
14
|
|
15
15
|
.card.mb-3
|
16
16
|
.card-body
|
@@ -0,0 +1,25 @@
|
|
1
|
+
-# In progress ballot
|
2
|
+
- ballot = Effective::Ballot.in_progress.where(user: current_user).first
|
3
|
+
- datatable = EffectiveResources.best('EffectivePollsAvailablePollsDatatable').new(self, namespace: :effective)
|
4
|
+
|
5
|
+
- if ballot.present?
|
6
|
+
%h2 In Progress #{et(Effective::Ballot)}
|
7
|
+
|
8
|
+
%p Your submission for #{ballot.poll} is incomplete
|
9
|
+
|
10
|
+
%p
|
11
|
+
Please
|
12
|
+
= link_to("Continue #{ballot.poll}", effective_polls.poll_ballot_build_path(ballot.poll, ballot, ballot.next_step), 'data-turbolinks' => false, class: 'btn btn-primary')
|
13
|
+
or you can
|
14
|
+
= link_to('Abandon', effective_polls.poll_ballot_path(ballot.poll, ballot), 'data-confirm': "Really delete #{ballot}?", 'data-method': :delete, class: 'btn btn-danger')
|
15
|
+
to begin again.
|
16
|
+
|
17
|
+
%hr
|
18
|
+
|
19
|
+
%h2 #{polls_name_label}
|
20
|
+
|
21
|
+
- if datatable.present?
|
22
|
+
%p The following #{etsd(Effective::Poll)} are available:
|
23
|
+
= render_datatable(datatable, simple: true)
|
24
|
+
- else
|
25
|
+
%p There are no available #{etsd(Effective::Poll)}. When there are, we'll show them here.
|
data/config/effective_polls.rb
CHANGED
@@ -3,19 +3,9 @@ EffectivePolls.setup do |config|
|
|
3
3
|
# Configure the Layout per controller, or all at once
|
4
4
|
# config.layout = { application: 'application', admin: 'admin' }
|
5
5
|
|
6
|
-
# Audience Scope Collection
|
7
|
-
#
|
8
|
-
# When creating a new poll, an Array of User scopes can be provided
|
9
|
-
# The User model must respond to these
|
10
|
-
#
|
11
|
-
# config.audience_user_scopes = [:all, :registered]
|
12
|
-
# config.audience_user_scopes = [['All Users', :all], ['Registered Users', :registered]]
|
13
|
-
#
|
14
|
-
config.audience_user_scopes = [['All Users', :all]]
|
15
|
-
|
16
6
|
# Notifications Mailer Settings
|
17
7
|
#
|
18
|
-
# Schedule rake effective_polls:
|
8
|
+
# Schedule rake effective_polls:send_notifications to run every 10 minutes
|
19
9
|
# to send out email poll notifications
|
20
10
|
#
|
21
11
|
# Please see config/initializers/effective_resources.rb for default effective_* gem mailer settings
|
@@ -29,6 +19,7 @@ EffectivePolls.setup do |config|
|
|
29
19
|
# config.deliver_method = nil # The deliver method, deliver_later or deliver_now
|
30
20
|
# config.mailer_layout = nil # Default mailer layout
|
31
21
|
# config.mailer_sender = nil # Default From value
|
22
|
+
# config.mailer_froms = nil # Default Froms collection
|
32
23
|
# config.mailer_admin = nil # Default To value for Admin correspondence
|
33
24
|
|
34
25
|
# Use effective email templates for event notifications
|
@@ -0,0 +1,14 @@
|
|
1
|
+
en:
|
2
|
+
effective_polls:
|
3
|
+
name: 'Elections and Polls'
|
4
|
+
acronym: 'Polls'
|
5
|
+
|
6
|
+
activerecord:
|
7
|
+
models:
|
8
|
+
effective/poll: 'Poll'
|
9
|
+
effective/poll_question: 'Poll Question'
|
10
|
+
effective/poll_question_option: 'Poll Question Option'
|
11
|
+
effective/poll_notification: 'Poll Notification'
|
12
|
+
effective/ballot: 'Ballot'
|
13
|
+
effective/ballot_response: 'Ballot Response'
|
14
|
+
effective/ballot_response_option: 'Ballot Response Option'
|
data/config/routes.rb
CHANGED
@@ -5,17 +5,14 @@ end
|
|
5
5
|
EffectivePolls::Engine.routes.draw do
|
6
6
|
scope module: 'effective' do
|
7
7
|
resources :polls, only: [:show] do
|
8
|
-
resources :ballots, only: [:new, :show] do
|
8
|
+
resources :ballots, only: [:new, :show, :destroy] do
|
9
9
|
resources :build, controller: :ballots, only: [:show, :update]
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
namespace :admin do
|
15
|
-
resources :polls
|
16
|
-
get :results, on: :member
|
17
|
-
end
|
18
|
-
|
15
|
+
resources :polls
|
19
16
|
resources :poll_notifications, except: [:show]
|
20
17
|
resources :poll_questions, except: [:show]
|
21
18
|
end
|
@@ -8,6 +8,8 @@ class CreateEffectivePolls < ActiveRecord::Migration[6.0]
|
|
8
8
|
t.datetime :end_at
|
9
9
|
|
10
10
|
t.string :audience
|
11
|
+
|
12
|
+
t.string :audience_class_name
|
11
13
|
t.text :audience_scope
|
12
14
|
|
13
15
|
t.datetime :updated_at
|
@@ -15,7 +17,7 @@ class CreateEffectivePolls < ActiveRecord::Migration[6.0]
|
|
15
17
|
end
|
16
18
|
|
17
19
|
create_table :poll_notifications do |t|
|
18
|
-
t.
|
20
|
+
t.references :poll, polymorphic: false
|
19
21
|
|
20
22
|
t.string :category
|
21
23
|
t.integer :reminder
|
@@ -32,7 +34,7 @@ class CreateEffectivePolls < ActiveRecord::Migration[6.0]
|
|
32
34
|
end
|
33
35
|
|
34
36
|
create_table :poll_questions do |t|
|
35
|
-
t.
|
37
|
+
t.references :poll, polymorphic: false
|
36
38
|
|
37
39
|
t.string :title
|
38
40
|
t.string :category
|
@@ -45,7 +47,7 @@ class CreateEffectivePolls < ActiveRecord::Migration[6.0]
|
|
45
47
|
end
|
46
48
|
|
47
49
|
create_table :poll_question_options do |t|
|
48
|
-
t.
|
50
|
+
t.references :poll_question, polymorphic: false
|
49
51
|
|
50
52
|
t.string :title
|
51
53
|
t.integer :position
|
@@ -55,8 +57,8 @@ class CreateEffectivePolls < ActiveRecord::Migration[6.0]
|
|
55
57
|
end
|
56
58
|
|
57
59
|
create_table :ballots do |t|
|
58
|
-
t.
|
59
|
-
t.
|
60
|
+
t.references :poll, polymorphic: false
|
61
|
+
t.references :user, polymorphic: true
|
60
62
|
|
61
63
|
t.string :token
|
62
64
|
t.text :wizard_steps
|
@@ -67,9 +69,9 @@ class CreateEffectivePolls < ActiveRecord::Migration[6.0]
|
|
67
69
|
end
|
68
70
|
|
69
71
|
create_table :ballot_responses do |t|
|
70
|
-
t.
|
71
|
-
t.
|
72
|
-
t.
|
72
|
+
t.references :ballot, polymorphic: false
|
73
|
+
t.references :poll, polymorphic: false
|
74
|
+
t.references :poll_question, polymorphic: false
|
73
75
|
|
74
76
|
t.date :date
|
75
77
|
t.string :email
|
@@ -82,8 +84,8 @@ class CreateEffectivePolls < ActiveRecord::Migration[6.0]
|
|
82
84
|
end
|
83
85
|
|
84
86
|
create_table :ballot_response_options do |t|
|
85
|
-
t.
|
86
|
-
t.
|
87
|
+
t.references :ballot_response, polymorphic: false
|
88
|
+
t.references :poll_question_option, polymorphic: false
|
87
89
|
|
88
90
|
t.datetime :updated_at
|
89
91
|
t.datetime :created_at
|
data/db/seeds.rb
CHANGED
@@ -9,7 +9,8 @@ def build_effective_poll
|
|
9
9
|
title: 'Effective Poll',
|
10
10
|
start_at: (Time.zone.now + 1.day).beginning_of_day,
|
11
11
|
end_at: (Time.zone.now + 1.day).end_of_day,
|
12
|
-
audience: 'All Users'
|
12
|
+
audience: 'All Users',
|
13
|
+
audience_class_name: 'User'
|
13
14
|
)
|
14
15
|
|
15
16
|
build_poll_question(poll, Effective::PollQuestion::CATEGORIES)
|
@@ -7,5 +7,12 @@ module EffectivePolls
|
|
7
7
|
eval File.read("#{config.root}/config/effective_polls.rb")
|
8
8
|
end
|
9
9
|
|
10
|
+
# Include effective_polls_user concern and allow any ActiveRecord object to call it
|
11
|
+
initializer 'effective_polls.active_record' do |app|
|
12
|
+
app.config.to_prepare do
|
13
|
+
ActiveRecord::Base.extend(EffectivePollsUser::Base)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
10
17
|
end
|
11
18
|
end
|
data/lib/effective_polls.rb
CHANGED
@@ -7,10 +7,8 @@ module EffectivePolls
|
|
7
7
|
|
8
8
|
def self.config_keys
|
9
9
|
[
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:layout, :audience_user_scopes,
|
13
|
-
:mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_admin, :mailer_subject, :use_effective_email_templates
|
10
|
+
:layout,
|
11
|
+
:mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_froms, :mailer_admin, :mailer_subject, :use_effective_email_templates
|
14
12
|
]
|
15
13
|
end
|
16
14
|
|
@@ -1,23 +1,34 @@
|
|
1
|
-
# rake effective_polls:
|
1
|
+
# rake effective_polls:send_notifications
|
2
2
|
|
3
3
|
namespace :effective_polls do
|
4
4
|
desc 'Send email notifications for effective polls'
|
5
|
-
task
|
6
|
-
|
5
|
+
task send_notifications: :environment do
|
6
|
+
puts 'Sending notifications'
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
notified = notification.notify!
|
11
|
-
puts "Sent #{notification.category} for #{notification.poll}" if notified
|
12
|
-
rescue => e
|
13
|
-
if defined?(ExceptionNotifier)
|
14
|
-
ExceptionNotifier.notify_exception(e, data: { poll_notification_id: notification.id, poll_id: notification.poll_id })
|
15
|
-
end
|
8
|
+
table = ActiveRecord::Base.connection.table_exists?(:poll_notifications)
|
9
|
+
blank_tenant = defined?(Tenant) && Tenant.current.blank?
|
16
10
|
|
17
|
-
|
11
|
+
if table && !blank_tenant
|
12
|
+
poll_notifications = Effective::PollNotification.deep.notifiable
|
13
|
+
|
14
|
+
poll_notifications.find_each do |notification|
|
15
|
+
begin
|
16
|
+
notified = notification.notify!
|
17
|
+
puts "Sent #{notification.category} for #{notification.poll}" if notified
|
18
|
+
rescue StandardError => e
|
19
|
+
data = { poll_notification_id: notification.id, poll_id: notification.poll_id }
|
20
|
+
ExceptionNotifier.notify_exception(e, data: data) if defined?(ExceptionNotifier)
|
21
|
+
puts "Error with effective poll_notification #{notification.id}: #{e.errors.inspect}"
|
22
|
+
end
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
21
26
|
puts 'All done'
|
22
27
|
end
|
28
|
+
|
29
|
+
# Deprecated version
|
30
|
+
task notify: :environment do
|
31
|
+
Rake::Task['effective_polls:send_notifications'].invoke
|
32
|
+
end
|
33
|
+
|
23
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_polls
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -227,9 +227,10 @@ files:
|
|
227
227
|
- app/datatables/admin/effective_poll_questions_datatable.rb
|
228
228
|
- app/datatables/admin/effective_poll_results_datatable.rb
|
229
229
|
- app/datatables/admin/effective_polls_datatable.rb
|
230
|
-
- app/datatables/
|
230
|
+
- app/datatables/effective_polls_available_polls_datatable.rb
|
231
231
|
- app/helpers/effective_polls_helper.rb
|
232
232
|
- app/mailers/effective/polls_mailer.rb
|
233
|
+
- app/models/concerns/effective_polls_user.rb
|
233
234
|
- app/models/effective/ballot.rb
|
234
235
|
- app/models/effective/ballot_response.rb
|
235
236
|
- app/models/effective/ballot_response_option.rb
|
@@ -247,7 +248,7 @@ files:
|
|
247
248
|
- app/views/admin/polls/_form.html.haml
|
248
249
|
- app/views/admin/polls/_form_content.html.haml
|
249
250
|
- app/views/admin/polls/_form_poll.html.haml
|
250
|
-
- app/views/admin/polls/
|
251
|
+
- app/views/admin/polls/_poll.html.haml
|
251
252
|
- app/views/effective/ballot_responses/_ballot_response.html.haml
|
252
253
|
- app/views/effective/ballot_responses/_fields.html.haml
|
253
254
|
- app/views/effective/ballot_responses/fields/_choose_one.html.haml
|
@@ -277,6 +278,8 @@ files:
|
|
277
278
|
- app/views/effective/ballot_responses/responses/_short_answer.html.haml
|
278
279
|
- app/views/effective/ballot_responses/responses/_upload_file.html.haml
|
279
280
|
- app/views/effective/ballots/_ballot.html.haml
|
281
|
+
- app/views/effective/ballots/_content.html.haml
|
282
|
+
- app/views/effective/ballots/_layout.html.haml
|
280
283
|
- app/views/effective/ballots/complete.html.haml
|
281
284
|
- app/views/effective/ballots/start.html.haml
|
282
285
|
- app/views/effective/ballots/submit.html.haml
|
@@ -297,12 +300,14 @@ files:
|
|
297
300
|
- app/views/effective/poll_results/results/_select_up_to_5.html.haml
|
298
301
|
- app/views/effective/poll_results/results/_short_answer.html.haml
|
299
302
|
- app/views/effective/poll_results/results/_upload_file.html.haml
|
303
|
+
- app/views/effective/polls/_dashboard.html.haml
|
300
304
|
- app/views/effective/polls_mailer/poll_before_poll_ends.liquid
|
301
305
|
- app/views/effective/polls_mailer/poll_reminder.liquid
|
302
306
|
- app/views/effective/polls_mailer/poll_upcoming_reminder.liquid
|
303
307
|
- app/views/effective/polls_mailer/poll_when_poll_ends.liquid
|
304
308
|
- app/views/effective/polls_mailer/poll_when_poll_starts.liquid
|
305
309
|
- config/effective_polls.rb
|
310
|
+
- config/locales/effective_polls.yml
|
306
311
|
- config/routes.rb
|
307
312
|
- db/migrate/101_create_effective_polls.rb
|
308
313
|
- db/seeds.rb
|