effective_polls 0.2.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +2 -2
- data/Rakefile +5 -19
- 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 -19
- data/config/locales/effective_polls.yml +14 -0
- data/config/routes.rb +2 -5
- data/db/migrate/{01_create_effective_polls.rb.erb → 101_create_effective_polls.rb} +19 -17
- data/db/seeds.rb +36 -0
- 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/generators/effective_polls/install_generator.rb +1 -9
- data/lib/tasks/effective_polls_tasks.rake +23 -12
- metadata +144 -12
- 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
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Works with action_text for content bodies, and active_storage for file uploads.
|
|
|
10
10
|
|
|
11
11
|
## Getting Started
|
|
12
12
|
|
|
13
|
-
This requires Rails 6
|
|
13
|
+
This requires Rails 6 and Twitter Bootstrap 4 and just works with Devise.
|
|
14
14
|
|
|
15
15
|
Please first install the [effective_datatables](https://github.com/code-and-effect/effective_datatables) gem.
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ Please download and install the [Twitter Bootstrap4](http://getbootstrap.com)
|
|
|
19
19
|
Add to your Gemfile:
|
|
20
20
|
|
|
21
21
|
```ruby
|
|
22
|
-
gem 'haml
|
|
22
|
+
gem 'haml'
|
|
23
23
|
gem 'effective_polls'
|
|
24
24
|
```
|
|
25
25
|
|
data/Rakefile
CHANGED
|
@@ -1,27 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
require 'bundler/setup'
|
|
3
|
-
rescue LoadError
|
|
4
|
-
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
require 'rdoc/task'
|
|
8
|
-
|
|
9
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
|
10
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
11
|
-
rdoc.title = 'EffectivePolls'
|
|
12
|
-
rdoc.options << '--line-numbers'
|
|
13
|
-
rdoc.rdoc_files.include('README.md')
|
|
14
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
-
end
|
|
1
|
+
require "bundler/setup"
|
|
16
2
|
|
|
17
3
|
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
|
18
|
-
load
|
|
4
|
+
load "rails/tasks/engine.rake"
|
|
19
5
|
|
|
20
|
-
load
|
|
6
|
+
load "rails/tasks/statistics.rake"
|
|
21
7
|
|
|
22
|
-
require
|
|
8
|
+
require "bundler/gem_tasks"
|
|
23
9
|
|
|
24
|
-
require
|
|
10
|
+
require "rake/testtask"
|
|
25
11
|
|
|
26
12
|
Rake::TestTask.new(:test) do |t|
|
|
27
13
|
t.libs << 'test'
|
|
@@ -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
|