test_redmine_vz 0.0.24
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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/README.md +71 -0
- data/Rakefile +20 -0
- data/config/currency_iso.json +2532 -0
- data/doc/CHANGELOG +55 -0
- data/doc/LICENSE.txt +339 -0
- data/lib/redmine_crm.rb +67 -0
- data/lib/redmine_crm/currency.rb +439 -0
- data/lib/redmine_crm/currency/formatting.rb +227 -0
- data/lib/redmine_crm/currency/heuristics.rb +151 -0
- data/lib/redmine_crm/currency/loader.rb +24 -0
- data/lib/redmine_crm/helpers/tags_helper.rb +15 -0
- data/lib/redmine_crm/helpers/vote_helper.rb +38 -0
- data/lib/redmine_crm/liquid/drops/issues_drop.rb +61 -0
- data/lib/redmine_crm/liquid/drops/news_drop.rb +45 -0
- data/lib/redmine_crm/liquid/drops/projects_drop.rb +78 -0
- data/lib/redmine_crm/liquid/drops/users_drop.rb +59 -0
- data/lib/redmine_crm/liquid/filters.rb +85 -0
- data/lib/redmine_crm/money_helper.rb +67 -0
- data/lib/redmine_crm/rcrm_acts_as_taggable.rb +342 -0
- data/lib/redmine_crm/rcrm_acts_as_viewed.rb +287 -0
- data/lib/redmine_crm/rcrm_acts_as_votable.rb +79 -0
- data/lib/redmine_crm/rcrm_acts_as_voter.rb +27 -0
- data/lib/redmine_crm/tag.rb +81 -0
- data/lib/redmine_crm/tag_list.rb +112 -0
- data/lib/redmine_crm/tagging.rb +20 -0
- data/lib/redmine_crm/version.rb +3 -0
- data/lib/redmine_crm/votable.rb +334 -0
- data/lib/redmine_crm/vote.rb +30 -0
- data/lib/redmine_crm/voter.rb +136 -0
- data/redmine_crm.gemspec +22 -0
- data/test/acts_as_taggable_test.rb +384 -0
- data/test/currency_test.rb +292 -0
- data/test/database.yml +17 -0
- data/test/fixtures/issue.rb +14 -0
- data/test/fixtures/issues.yml +12 -0
- data/test/fixtures/taggings.yml +32 -0
- data/test/fixtures/tags.yml +11 -0
- data/test/fixtures/user.rb +7 -0
- data/test/fixtures/users.yml +5 -0
- data/test/fixtures/votable_caches.yml +2 -0
- data/test/fixtures/votables.yml +4 -0
- data/test/fixtures/vote_classes.rb +54 -0
- data/test/fixtures/voters.yml +6 -0
- data/test/liquid_test.rb +80 -0
- data/test/money_helper_test.rb +12 -0
- data/test/schema.rb +100 -0
- data/test/tag_test.rb +63 -0
- data/test/tagging_test.rb +14 -0
- data/test/tags_helper_test.rb +29 -0
- data/test/test_helper.rb +118 -0
- data/test/viewed_test.rb +45 -0
- data/test/votable_model_test.rb +478 -0
- data/test/votable_test.rb +17 -0
- data/test/vote_helper_test.rb +28 -0
- data/test/voter_model_test.rb +296 -0
- metadata +141 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
class TagList < Array
|
3
|
+
cattr_accessor :delimiter
|
4
|
+
self.delimiter = ','
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
add(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Add tags to the tag_list. Duplicate or blank tags will be ignored.
|
11
|
+
#
|
12
|
+
# tag_list.add("Fun", "Happy")
|
13
|
+
#
|
14
|
+
# Use the <tt>:parse</tt> option to add an unparsed tag string.
|
15
|
+
#
|
16
|
+
# tag_list.add("Fun, Happy", :parse => true)
|
17
|
+
def add(*names)
|
18
|
+
extract_and_apply_options!(names)
|
19
|
+
concat(names)
|
20
|
+
clean!
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# Remove specific tags from the tag_list.
|
25
|
+
#
|
26
|
+
# tag_list.remove("Sad", "Lonely")
|
27
|
+
#
|
28
|
+
# Like #add, the <tt>:parse</tt> option can be used to remove multiple tags in a string.
|
29
|
+
#
|
30
|
+
# tag_list.remove("Sad, Lonely", :parse => true)
|
31
|
+
def remove(*names)
|
32
|
+
extract_and_apply_options!(names)
|
33
|
+
delete_if { |name| names.include?(name) }
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# Toggle the presence of the given tags.
|
38
|
+
# If a tag is already in the list it is removed, otherwise it is added.
|
39
|
+
def toggle(*names)
|
40
|
+
extract_and_apply_options!(names)
|
41
|
+
|
42
|
+
names.each do |name|
|
43
|
+
include?(name) ? delete(name) : push(name)
|
44
|
+
end
|
45
|
+
|
46
|
+
clean!
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Transform the tag_list into a tag string suitable for edting in a form.
|
51
|
+
# The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary.
|
52
|
+
#
|
53
|
+
# tag_list = TagList.new("Round", "Square,Cube")
|
54
|
+
# tag_list.to_s # 'Round, "Square,Cube"'
|
55
|
+
def to_s
|
56
|
+
clean!
|
57
|
+
|
58
|
+
map do |name|
|
59
|
+
name.include?(delimiter) ? "\"#{name}\"" : name
|
60
|
+
end.join(delimiter.ends_with?(" ") ? delimiter : "#{delimiter} ")
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
# Remove whitespace, duplicates, and blanks.
|
65
|
+
def clean!
|
66
|
+
reject!(&:blank?)
|
67
|
+
map!(&:strip)
|
68
|
+
uniq!
|
69
|
+
end
|
70
|
+
|
71
|
+
def extract_and_apply_options!(args)
|
72
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
73
|
+
options.assert_valid_keys :parse
|
74
|
+
|
75
|
+
if options[:parse]
|
76
|
+
args.map! { |a| self.class.from(a) }
|
77
|
+
end
|
78
|
+
|
79
|
+
args.flatten!
|
80
|
+
end
|
81
|
+
|
82
|
+
class << self
|
83
|
+
# Returns a new TagList using the given tag string.
|
84
|
+
#
|
85
|
+
# tag_list = TagList.from("One , Two, Three")
|
86
|
+
# tag_list # ["One", "Two", "Three"]
|
87
|
+
def from(source)
|
88
|
+
tag_list = new
|
89
|
+
|
90
|
+
case source
|
91
|
+
when Array
|
92
|
+
tag_list.add(source)
|
93
|
+
else
|
94
|
+
string = source.to_s.dup
|
95
|
+
|
96
|
+
# Parse the quoted tags
|
97
|
+
[
|
98
|
+
/\s*#{delimiter}\s*(['"])(.*?)\1\s*/,
|
99
|
+
/^\s*(['"])(.*?)\1\s*#{delimiter}?/
|
100
|
+
].each do |re|
|
101
|
+
string.gsub!(re) { tag_list << $2; "" }
|
102
|
+
end
|
103
|
+
|
104
|
+
tag_list.add(string.split(delimiter))
|
105
|
+
end
|
106
|
+
|
107
|
+
tag_list
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
|
3
|
+
class Tagging < ActiveRecord::Base #:nodoc:
|
4
|
+
belongs_to :tag
|
5
|
+
belongs_to :taggable, :polymorphic => true
|
6
|
+
|
7
|
+
after_destroy :destroy_tag_if_unused
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def destroy_tag_if_unused
|
12
|
+
if Tag.destroy_unused
|
13
|
+
if tag.taggings.count.zero?
|
14
|
+
tag.destroy
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,334 @@
|
|
1
|
+
require 'redmine_crm/helpers/vote_helper'
|
2
|
+
|
3
|
+
module RedmineCrm
|
4
|
+
module ActsAsVotable
|
5
|
+
module Votable
|
6
|
+
|
7
|
+
include ActsAsVotable::Helpers::Words
|
8
|
+
|
9
|
+
def self.included base
|
10
|
+
|
11
|
+
# allow the user to define these himself
|
12
|
+
aliases = {
|
13
|
+
|
14
|
+
:vote_up => [
|
15
|
+
:up_by, :upvote_by, :like_by, :liked_by,
|
16
|
+
:up_from, :upvote_from, :upvote_by, :like_from, :liked_from, :vote_from
|
17
|
+
],
|
18
|
+
|
19
|
+
:vote_down => [
|
20
|
+
:down_by, :downvote_by, :dislike_by, :disliked_by,
|
21
|
+
:down_from, :downvote_from, :downvote_by, :dislike_by, :disliked_by
|
22
|
+
],
|
23
|
+
|
24
|
+
:get_up_votes => [
|
25
|
+
:get_true_votes, :get_ups, :get_upvotes, :get_likes, :get_positives, :get_for_votes,
|
26
|
+
],
|
27
|
+
|
28
|
+
:get_down_votes => [
|
29
|
+
:get_false_votes, :get_downs, :get_downvotes, :get_dislikes, :get_negatives
|
30
|
+
],
|
31
|
+
:unvote_by => [
|
32
|
+
:unvote_up, :unvote_down, :unliked_by, :undisliked_by
|
33
|
+
]
|
34
|
+
}
|
35
|
+
|
36
|
+
base.class_eval do
|
37
|
+
has_many :votes_for, :class_name => 'RedmineCrm::ActsAsVotable::Vote', :as => :votable, :dependent => :destroy do
|
38
|
+
def voters
|
39
|
+
includes(:voter).map(&:voter)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
aliases.each do |method, links|
|
44
|
+
links.each do |new_method|
|
45
|
+
alias_method(new_method, method)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_accessor :vote_registered
|
53
|
+
|
54
|
+
def vote_registered?
|
55
|
+
return self.vote_registered
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_conditions
|
59
|
+
{
|
60
|
+
:votable_id => self.id,
|
61
|
+
:votable_type => self.class.base_class.name.to_s
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# voting
|
66
|
+
def vote_by args = {}
|
67
|
+
|
68
|
+
options = {
|
69
|
+
:vote => true,
|
70
|
+
:vote_scope => nil
|
71
|
+
}.merge(args)
|
72
|
+
|
73
|
+
self.vote_registered = false
|
74
|
+
|
75
|
+
if options[:voter].nil?
|
76
|
+
return false
|
77
|
+
end
|
78
|
+
|
79
|
+
# find the vote
|
80
|
+
_votes_ = find_votes_for({
|
81
|
+
:voter_id => options[:voter].id,
|
82
|
+
:vote_scope => options[:vote_scope],
|
83
|
+
:voter_type => options[:voter].class.base_class.name
|
84
|
+
})
|
85
|
+
|
86
|
+
if _votes_.count == 0 or options[:duplicate]
|
87
|
+
# this voter has never voted
|
88
|
+
vote = RedmineCrm::ActsAsVotable::Vote.new(
|
89
|
+
:votable => self,
|
90
|
+
:voter => options[:voter],
|
91
|
+
:vote_scope => options[:vote_scope]
|
92
|
+
)
|
93
|
+
else
|
94
|
+
# this voter is potentially changing his vote
|
95
|
+
vote = _votes_.last
|
96
|
+
end
|
97
|
+
|
98
|
+
last_update = vote.updated_at
|
99
|
+
|
100
|
+
vote.vote_flag = votable_words.meaning_of(options[:vote])
|
101
|
+
|
102
|
+
#Allowing for a vote_weight to be associated with every vote. Could change with every voter object
|
103
|
+
vote.vote_weight = (options[:vote_weight].to_i if options[:vote_weight].present?) || 1
|
104
|
+
|
105
|
+
if vote.save
|
106
|
+
self.vote_registered = true if last_update != vote.updated_at
|
107
|
+
update_cached_votes options[:vote_scope]
|
108
|
+
return true
|
109
|
+
else
|
110
|
+
self.vote_registered = false
|
111
|
+
return false
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
def unvote args = {}
|
117
|
+
return false if args[:voter].nil?
|
118
|
+
_votes_ = find_votes_for(:voter_id => args[:voter].id, :vote_scope => args[:vote_scope], :voter_type => args[:voter].class.base_class.name)
|
119
|
+
|
120
|
+
return true if _votes_.size == 0
|
121
|
+
_votes_.each(&:destroy)
|
122
|
+
update_cached_votes args[:vote_scope]
|
123
|
+
self.vote_registered = false if votes_for.count == 0
|
124
|
+
return true
|
125
|
+
end
|
126
|
+
|
127
|
+
def vote_up voter, options={}
|
128
|
+
self.vote_by :voter => voter, :vote => true, :vote_scope => options[:vote_scope], :vote_weight => options[:vote_weight]
|
129
|
+
end
|
130
|
+
|
131
|
+
def vote_down voter, options={}
|
132
|
+
self.vote_by :voter => voter, :vote => false, :vote_scope => options[:vote_scope], :vote_weight => options[:vote_weight]
|
133
|
+
end
|
134
|
+
|
135
|
+
def unvote_by voter, options = {}
|
136
|
+
self.unvote :voter => voter, :vote_scope => options[:vote_scope] #Does not need vote_weight since the votes_for are anyway getting destroyed
|
137
|
+
end
|
138
|
+
|
139
|
+
def scope_cache_field field, vote_scope
|
140
|
+
return field if vote_scope.nil?
|
141
|
+
|
142
|
+
case field
|
143
|
+
when :cached_votes_total=
|
144
|
+
"cached_scoped_#{vote_scope}_votes_total="
|
145
|
+
when :cached_votes_total
|
146
|
+
"cached_scoped_#{vote_scope}_votes_total"
|
147
|
+
when :cached_votes_up=
|
148
|
+
"cached_scoped_#{vote_scope}_votes_up="
|
149
|
+
when :cached_votes_up
|
150
|
+
"cached_scoped_#{vote_scope}_votes_up"
|
151
|
+
when :cached_votes_down=
|
152
|
+
"cached_scoped_#{vote_scope}_votes_down="
|
153
|
+
when :cached_votes_down
|
154
|
+
"cached_scoped_#{vote_scope}_votes_down"
|
155
|
+
when :cached_votes_score=
|
156
|
+
"cached_scoped_#{vote_scope}_votes_score="
|
157
|
+
when :cached_votes_score
|
158
|
+
"cached_scoped_#{vote_scope}_votes_score"
|
159
|
+
when :cached_weighted_total
|
160
|
+
"cached_weighted_#{vote_scope}_total"
|
161
|
+
when :cached_weighted_total=
|
162
|
+
"cached_weighted_#{vote_scope}_total="
|
163
|
+
when :cached_weighted_score
|
164
|
+
"cached_weighted_#{vote_scope}_score"
|
165
|
+
when :cached_weighted_score=
|
166
|
+
"cached_weighted_#{vote_scope}_score="
|
167
|
+
when :cached_weighted_average
|
168
|
+
"cached_weighted_#{vote_scope}_average"
|
169
|
+
when :cached_weighted_average=
|
170
|
+
"cached_weighted_#{vote_scope}_average="
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# caching
|
175
|
+
def update_cached_votes vote_scope = nil
|
176
|
+
|
177
|
+
updates = {}
|
178
|
+
|
179
|
+
if self.respond_to?(:cached_votes_total=)
|
180
|
+
updates[:cached_votes_total] = count_votes_total(true)
|
181
|
+
end
|
182
|
+
|
183
|
+
if self.respond_to?(:cached_votes_up=)
|
184
|
+
updates[:cached_votes_up] = count_votes_up(true)
|
185
|
+
end
|
186
|
+
|
187
|
+
if self.respond_to?(:cached_votes_down=)
|
188
|
+
updates[:cached_votes_down] = count_votes_down(true)
|
189
|
+
end
|
190
|
+
|
191
|
+
if self.respond_to?(:cached_votes_score=)
|
192
|
+
updates[:cached_votes_score] = (
|
193
|
+
(updates[:cached_votes_up] || count_votes_up(true)) -
|
194
|
+
(updates[:cached_votes_down] || count_votes_down(true))
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
if self.respond_to?(:cached_weighted_total=)
|
199
|
+
updates[:cached_weighted_total] = weighted_total(true)
|
200
|
+
end
|
201
|
+
|
202
|
+
if self.respond_to?(:cached_weighted_score=)
|
203
|
+
updates[:cached_weighted_score] = weighted_score(true)
|
204
|
+
end
|
205
|
+
|
206
|
+
if self.respond_to?(:cached_weighted_average=)
|
207
|
+
updates[:cached_weighted_average] = weighted_average(true)
|
208
|
+
end
|
209
|
+
|
210
|
+
if vote_scope
|
211
|
+
if self.respond_to?(scope_cache_field :cached_votes_total=, vote_scope)
|
212
|
+
updates[scope_cache_field :cached_votes_total, vote_scope] = count_votes_total(true, vote_scope)
|
213
|
+
end
|
214
|
+
|
215
|
+
if self.respond_to?(scope_cache_field :cached_votes_up=, vote_scope)
|
216
|
+
updates[scope_cache_field :cached_votes_up, vote_scope] = count_votes_up(true, vote_scope)
|
217
|
+
end
|
218
|
+
|
219
|
+
if self.respond_to?(scope_cache_field :cached_votes_down=, vote_scope)
|
220
|
+
updates[scope_cache_field :cached_votes_down, vote_scope] = count_votes_down(true, vote_scope)
|
221
|
+
end
|
222
|
+
|
223
|
+
if self.respond_to?(scope_cache_field :cached_weighted_total=, vote_scope)
|
224
|
+
updates[scope_cache_field :cached_weighted_total, vote_scope] = weighted_total(true, vote_scope)
|
225
|
+
end
|
226
|
+
|
227
|
+
if self.respond_to?(scope_cache_field :cached_weighted_score=, vote_scope)
|
228
|
+
updates[scope_cache_field :cached_weighted_score, vote_scope] = weighted_score(true, vote_scope)
|
229
|
+
end
|
230
|
+
|
231
|
+
if self.respond_to?(scope_cache_field :cached_votes_score=, vote_scope)
|
232
|
+
updates[scope_cache_field :cached_votes_score, vote_scope] = (
|
233
|
+
(updates[scope_cache_field :cached_votes_up, vote_scope] || count_votes_up(true, vote_scope)) -
|
234
|
+
(updates[scope_cache_field :cached_votes_down, vote_scope] || count_votes_down(true, vote_scope))
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
if self.respond_to?(scope_cache_field :cached_weighted_average=, vote_scope)
|
239
|
+
updates[scope_cache_field :cached_weighted_average, vote_scope] = weighted_average(true, vote_scope)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
if (::ActiveRecord::VERSION::MAJOR == 3) && (::ActiveRecord::VERSION::MINOR != 0)
|
244
|
+
self.update_attributes(updates, :without_protection => true) if updates.size > 0
|
245
|
+
else
|
246
|
+
self.update_attributes(updates) if updates.size > 0
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
# results
|
253
|
+
def find_votes_for extra_conditions = {}
|
254
|
+
votes_for.where(extra_conditions)
|
255
|
+
end
|
256
|
+
|
257
|
+
def get_up_votes options={}
|
258
|
+
vote_scope_hash = scope_or_empty_hash(options[:vote_scope])
|
259
|
+
find_votes_for({:vote_flag => true}.merge(vote_scope_hash))
|
260
|
+
end
|
261
|
+
|
262
|
+
def get_down_votes options={}
|
263
|
+
vote_scope_hash = scope_or_empty_hash(options[:vote_scope])
|
264
|
+
find_votes_for({:vote_flag => false}.merge(vote_scope_hash))
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
# counting
|
269
|
+
def count_votes_total skip_cache = false, vote_scope = nil
|
270
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_total, vote_scope)
|
271
|
+
return self.send(scope_cache_field :cached_votes_total, vote_scope)
|
272
|
+
end
|
273
|
+
find_votes_for(scope_or_empty_hash(vote_scope)).count
|
274
|
+
end
|
275
|
+
|
276
|
+
def count_votes_up skip_cache = false, vote_scope = nil
|
277
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_up, vote_scope)
|
278
|
+
return self.send(scope_cache_field :cached_votes_up, vote_scope)
|
279
|
+
end
|
280
|
+
get_up_votes(:vote_scope => vote_scope).count
|
281
|
+
end
|
282
|
+
|
283
|
+
def count_votes_down skip_cache = false, vote_scope = nil
|
284
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_down, vote_scope)
|
285
|
+
return self.send(scope_cache_field :cached_votes_down, vote_scope)
|
286
|
+
end
|
287
|
+
get_down_votes(:vote_scope => vote_scope).count
|
288
|
+
end
|
289
|
+
|
290
|
+
def weighted_total skip_cache = false, vote_scope = nil
|
291
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_total, vote_scope)
|
292
|
+
return self.send(scope_cache_field :cached_weighted_total, vote_scope)
|
293
|
+
end
|
294
|
+
ups = get_up_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
295
|
+
downs = get_down_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
296
|
+
ups + downs
|
297
|
+
end
|
298
|
+
|
299
|
+
def weighted_score skip_cache = false, vote_scope = nil
|
300
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_score, vote_scope)
|
301
|
+
return self.send(scope_cache_field :cached_weighted_score, vote_scope)
|
302
|
+
end
|
303
|
+
ups = get_up_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
304
|
+
downs = get_down_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
305
|
+
ups - downs
|
306
|
+
end
|
307
|
+
|
308
|
+
def weighted_average skip_cache = false, vote_scope = nil
|
309
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_average, vote_scope)
|
310
|
+
return self.send(scope_cache_field :cached_weighted_average, vote_scope)
|
311
|
+
end
|
312
|
+
|
313
|
+
count = count_votes_total(skip_cache, vote_scope).to_i
|
314
|
+
if count > 0
|
315
|
+
weighted_score(skip_cache, vote_scope).to_f / count
|
316
|
+
else
|
317
|
+
0.0
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
# voters
|
322
|
+
def voted_on_by? voter
|
323
|
+
votes = find_votes_for :voter_id => voter.id, :voter_type => voter.class.base_class.name
|
324
|
+
votes.count > 0
|
325
|
+
end
|
326
|
+
|
327
|
+
private
|
328
|
+
|
329
|
+
def scope_or_empty_hash(vote_scope)
|
330
|
+
vote_scope ? { :vote_scope => vote_scope } : {}
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|