recognition 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +59 -29
- data/lib/generators/recognition/gift_generator.rb +25 -0
- data/lib/generators/recognition/voucher_generator.rb +3 -1
- data/lib/recognition/database.rb +14 -9
- data/lib/recognition/extensions/active_record.rb +17 -5
- data/lib/recognition/models/gift.rb +8 -55
- data/lib/recognition/models/redeemable.rb +81 -0
- data/lib/recognition/models/voucher.rb +7 -72
- data/lib/recognition/version.rb +1 -1
- metadata +5 -3
data/README.md
CHANGED
@@ -80,11 +80,63 @@ app/controllers/profiles_controller.rb:
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
+
Example:
|
84
|
+
|
85
|
+
The following won't work:
|
86
|
+
|
87
|
+
class Post < ActiveRecord::Base
|
88
|
+
attr_accessible :title, :user_id
|
89
|
+
recognize :user, for: :foo, gain: 2
|
90
|
+
def foo
|
91
|
+
# do something useful
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
This one will:
|
96
|
+
|
97
|
+
class Post < ActiveRecord::Base
|
98
|
+
attr_accessible :title, :user_id
|
99
|
+
def foo
|
100
|
+
# do something useful
|
101
|
+
end
|
102
|
+
recognize :user, for: :foo, gain: 2
|
103
|
+
end
|
104
|
+
|
83
105
|
### Vouchers
|
84
106
|
|
107
|
+
Use an existing model or generate a new one using:
|
108
|
+
|
109
|
+
$ rails generate recogintion:voucher
|
110
|
+
|
111
|
+
Your model might have the following attributes:
|
112
|
+
|
113
|
+
* `:code` **required**
|
114
|
+
* `:amount` **required**
|
115
|
+
* `:expires_at` _optional_
|
116
|
+
* `:reusable` _optional_
|
117
|
+
|
118
|
+
You can specify the following extra parameters for vouchers:
|
119
|
+
|
120
|
+
* `:prefix` can be a number, string or method name or even an anonymous function.
|
121
|
+
* `:suffix` can be a number, string or method name or even an anonymous function.
|
122
|
+
|
123
|
+
app/models/voucher.rb:
|
124
|
+
|
125
|
+
class Voucher < ActiveRecord::Base
|
126
|
+
attr_accessible :code, :amount, :expires_at, :reusable
|
127
|
+
acts_as_voucher code_length: 14
|
128
|
+
end
|
129
|
+
|
130
|
+
Then, you may do:
|
131
|
+
|
132
|
+
voucher = Voucher.create!(amount: 20, expires_at: (DateTime.now + 1.day), reusable: true)
|
133
|
+
voucher.redeem current_user
|
134
|
+
|
135
|
+
### Gifts
|
136
|
+
|
85
137
|
Use an existing model or generate a new one using:
|
86
138
|
|
87
|
-
|
139
|
+
$ rails generate recogintion:gift
|
88
140
|
|
89
141
|
Your model might have the following attributes:
|
90
142
|
|
@@ -93,44 +145,22 @@ Your model might have the following attributes:
|
|
93
145
|
* `:expires_at` _optional_
|
94
146
|
* `:reusable` _optional_
|
95
147
|
|
96
|
-
You can specify the following extra parameters for
|
148
|
+
You can specify the following extra parameters for gifts:
|
97
149
|
|
98
150
|
* `:prefix` can be a number, string or method name or even an anonymous function.
|
99
151
|
* `:suffix` can be a number, string or method name or even an anonymous function.
|
100
152
|
|
101
|
-
app/models/
|
153
|
+
app/models/gift.rb:
|
102
154
|
|
103
|
-
class
|
155
|
+
class Gift < ActiveRecord::Base
|
104
156
|
attr_accessible :code, :amount, :expires_at, :reusable
|
105
|
-
|
157
|
+
acts_as_gift code_length: 14
|
106
158
|
end
|
107
159
|
|
108
160
|
Then, you may do:
|
109
161
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
## Example
|
114
|
-
The following won't work:
|
115
|
-
|
116
|
-
class Post < ActiveRecord::Base
|
117
|
-
attr_accessible :title, :user_id
|
118
|
-
recognize :user, for: :foo, gain: 2
|
119
|
-
def foo
|
120
|
-
# do something useful
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
This one will:
|
125
|
-
|
126
|
-
class Post < ActiveRecord::Base
|
127
|
-
attr_accessible :title, :user_id
|
128
|
-
def foo
|
129
|
-
# do something useful
|
130
|
-
end
|
131
|
-
recognize :user, for: :foo, gain: 2
|
132
|
-
end
|
133
|
-
|
162
|
+
gift = Gift.create!(amount: 20, expires_at: (DateTime.now + 1.day), reusable: true)
|
163
|
+
gift.redeem current_user
|
134
164
|
|
135
165
|
## Contributing
|
136
166
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Generators
|
3
|
+
class GiftGenerator < ::Rails::Generators::Base
|
4
|
+
desc "Generates a Recognition Gift"
|
5
|
+
|
6
|
+
def scaffold
|
7
|
+
generate 'scaffold gift code amount:integer reusable:boolean expires_at:datetime'
|
8
|
+
end
|
9
|
+
|
10
|
+
def set_defaults
|
11
|
+
line = "t.boolean :reusable"
|
12
|
+
gsub_file Dir.glob("db/migrate/*_create_gifts.rb").first, /(#{Regexp.escape(line)})/mi do |match|
|
13
|
+
"#{match}, default: false"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_stanza
|
18
|
+
line = "class Gift < ActiveRecord::Base"
|
19
|
+
gsub_file 'app/models/gift.rb', /(#{Regexp.escape(line)})/mi do |match|
|
20
|
+
"#{match}\n acts_as_gift code_length: 20 \n"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Recognition
|
2
2
|
module Generators
|
3
|
-
class VoucherGenerator < Rails::Generators::Base
|
3
|
+
class VoucherGenerator < ::Rails::Generators::Base
|
4
|
+
desc "Generates a Recognition Voucher"
|
5
|
+
|
4
6
|
def scaffold
|
5
7
|
generate 'scaffold voucher code amount:integer reusable:boolean expires_at:datetime'
|
6
8
|
end
|
data/lib/recognition/database.rb
CHANGED
@@ -29,17 +29,22 @@ module Recognition
|
|
29
29
|
Recognition.log 'foo', condition.to_s
|
30
30
|
condition[:bucket] ||= "#{ object.class.to_s.camelize }:#{ action }"
|
31
31
|
user = Recognition::Parser.parse_recognizable(object, condition[:recognizable], condition[:proc_params])
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
ground_total = user.recognition_counter(condition[:bucket]) + total
|
38
|
-
if condition[:maximum].nil? || ground_total <= condition[:maximum]
|
39
|
-
log(user.id, total.to_i, condition[:bucket])
|
32
|
+
# Do we have a valid user?
|
33
|
+
if user.respond_to?(:points)
|
34
|
+
if condition[:amount].nil? && condition[:gain].nil? && condition[:loss].nil?
|
35
|
+
Recognition.log 'validation', "Unable to determine points: no 'amount', 'gain' or 'loss' specified"
|
36
|
+
false
|
40
37
|
else
|
41
|
-
Recognition.
|
38
|
+
total = Recognition::Parser.parse_amount(condition[:amount], object, condition[:proc_params]) + Recognition::Parser.parse_amount(condition[:gain], object, condition[:proc_params]) - Recognition::Parser.parse_amount(condition[:loss], object, condition[:proc_params])
|
39
|
+
ground_total = user.recognition_counter(condition[:bucket]) + total
|
40
|
+
if condition[:maximum].nil? || ground_total <= condition[:maximum]
|
41
|
+
log(user.id, total.to_i, condition[:bucket])
|
42
|
+
else
|
43
|
+
Recognition.log 'validation', "Unable to add points: bucket maximum reached for bucket '#{condition[:bucket]}'"
|
44
|
+
end
|
42
45
|
end
|
46
|
+
else
|
47
|
+
Recognition.log 'validation', "Unable to add points to #{condition[:recognizable]}, make sure it 'acts_as_recognizable'"
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
@@ -53,16 +53,28 @@ module Recognition
|
|
53
53
|
after_save :recognize_creating
|
54
54
|
end
|
55
55
|
|
56
|
-
# to be called from user-model
|
57
56
|
def acts_as_voucher options = {}
|
58
57
|
require "recognition/models/voucher"
|
59
58
|
include Recognition::Models::Voucher
|
60
59
|
self.recognitions = options
|
61
|
-
cattr_accessor :
|
60
|
+
cattr_accessor :redemption_validators
|
62
61
|
def self.validates_voucher_redmeption validators
|
63
|
-
self.
|
64
|
-
self.
|
65
|
-
self.
|
62
|
+
self.redemption_validators ||= []
|
63
|
+
self.redemption_validators << validators
|
64
|
+
self.redemption_validators.flatten!
|
65
|
+
end
|
66
|
+
before_create :regenerate_code
|
67
|
+
end
|
68
|
+
|
69
|
+
def acts_as_gift options = {}
|
70
|
+
require "recognition/models/gift"
|
71
|
+
include Recognition::Models::Gift
|
72
|
+
self.recognitions = options
|
73
|
+
cattr_accessor :redemption_validators
|
74
|
+
def self.validates_gift_redmeption validators
|
75
|
+
self.redemption_validators ||= []
|
76
|
+
self.redemption_validators << validators
|
77
|
+
self.redemption_validators.flatten!
|
66
78
|
end
|
67
79
|
before_create :regenerate_code
|
68
80
|
end
|
@@ -1,65 +1,18 @@
|
|
1
|
+
require 'recognition/models/redeemable'
|
2
|
+
|
1
3
|
module Recognition
|
2
4
|
module Models
|
3
5
|
module Gift
|
4
|
-
|
5
|
-
|
6
|
-
suffix = Recognition::Database.parse_code_part(self.class.recognitions[:suffix], self)
|
7
|
-
l = (self.class.recognitions[:code_length] - (prefix.length + suffix.length)) || 10
|
8
|
-
dict = [('a'..'z'),('A'..'Z'),(0..9)].map{|i| i.to_a}.flatten
|
9
|
-
code = (1..l).map{ dict[rand(dict.length)] }.prepend(prefix).append(suffix).join
|
10
|
-
# Prevent code collision at all costs
|
11
|
-
if self.class.to_s.constantize.find_all_by_code(code).any?
|
12
|
-
regenerate_code
|
13
|
-
else
|
14
|
-
self.code = code
|
15
|
-
self
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def redeem recognizable
|
20
|
-
# Make sure we have an amount beforehand
|
21
|
-
if defined? self.amount
|
22
|
-
if self.redeemable? recognizable
|
23
|
-
# Call custom validators
|
24
|
-
if defined? self.class.gift_validators
|
25
|
-
self.class.gift_validators.each do |validator|
|
26
|
-
# quit if any validator returned false
|
27
|
-
return if send(validator) == false
|
28
|
-
end
|
29
|
-
end
|
30
|
-
# If all went well:
|
31
|
-
Database.redeem_gift recognizable.id, self.code, self.amount
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
6
|
+
include Recognition::Models::Redeemable
|
7
|
+
|
36
8
|
def redeemable? recognizable
|
37
|
-
|
38
|
-
pass = false
|
39
|
-
# only check if the gift did not expire
|
40
|
-
unless expired?
|
41
|
-
# has the gift ever been redeemed?
|
42
|
-
if Database.get_gift_transactions(self.code).any?
|
43
|
-
# has the gift ever been redeemed by this user?
|
44
|
-
if Database.get_user_gift(recognizable.id, code) != 0
|
45
|
-
pass = false
|
46
|
-
# is the gift reusable?
|
47
|
-
elsif defined?(self.reusable?) && self.reusable?
|
48
|
-
pass = true
|
49
|
-
end
|
50
|
-
else
|
51
|
-
pass = true
|
52
|
-
end
|
53
|
-
end
|
54
|
-
pass
|
9
|
+
recognizable.points >= self.amount && is_redeemable?(recognizable)
|
55
10
|
end
|
56
11
|
|
57
|
-
def
|
58
|
-
|
12
|
+
def execute_redemption id
|
13
|
+
actual_amount = (self.amount.to_i * -1)
|
14
|
+
Recognition::Database.redeem id, bucket, self.class.to_s.downcase, self.code, actual_amount
|
59
15
|
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
16
|
end
|
64
17
|
end
|
65
18
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Models
|
3
|
+
module Redeemable
|
4
|
+
def regenerate_code
|
5
|
+
prefix = Recognition::Parser.parse_code_part(self.class.recognitions[:prefix], self)
|
6
|
+
suffix = Recognition::Parser.parse_code_part(self.class.recognitions[:suffix], self)
|
7
|
+
l = (self.class.recognitions[:code_length] - (prefix.length + suffix.length)) || 10
|
8
|
+
dict = [('a'..'z'),('A'..'Z'),(0..9)].map{|i| i.to_a}.flatten
|
9
|
+
code = (1..l).map{ dict[rand(dict.length)] }.prepend(prefix).append(suffix).join
|
10
|
+
# Prevent code collision at all costs
|
11
|
+
if self.class.to_s.constantize.find_all_by_code(code).any?
|
12
|
+
regenerate_code
|
13
|
+
else
|
14
|
+
self.code = code
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def expired?
|
20
|
+
defined?(self.expires_at) && self.expires_at.present? && self.expires_at < DateTime.now
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_redeemable? recognizable
|
24
|
+
# default: not redeemable
|
25
|
+
pass = false
|
26
|
+
# only check if the redeemable did not expire
|
27
|
+
unless expired?
|
28
|
+
# has the redeemable ever been redeemed?
|
29
|
+
if transactions.any?
|
30
|
+
# has the redeemable ever been redeemed by this user?
|
31
|
+
if get_user_counter(recognizable.id) != 0
|
32
|
+
pass = false
|
33
|
+
# is the redeemable reusable?
|
34
|
+
elsif defined?(self.reusable?) && self.reusable?
|
35
|
+
pass = true
|
36
|
+
end
|
37
|
+
else
|
38
|
+
pass = true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
pass
|
42
|
+
end
|
43
|
+
|
44
|
+
def redeem recognizable
|
45
|
+
# Make sure we have an amount beforehand
|
46
|
+
if defined? self.amount
|
47
|
+
if self.redeemable? recognizable
|
48
|
+
# Call custom validators
|
49
|
+
if defined? self.class.redemption_validators
|
50
|
+
self.class.redemption_validators.each do |validator|
|
51
|
+
# quit if any validator returned false
|
52
|
+
if send(validator) == false
|
53
|
+
Recognition.log self.class.to_s.to_sym, "validation error for #{self.class.to_s}:#{self.id}"
|
54
|
+
return
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
# If all went well:
|
59
|
+
execute_redemption recognizable.id
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def bucket
|
66
|
+
"#{self.class.to_s.downcase}:#{ self.code }"
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_user_counter id
|
70
|
+
Recognition::Database.get_counter "user:#{id}", bucket
|
71
|
+
end
|
72
|
+
|
73
|
+
def transactions page = 0, per = 20
|
74
|
+
start = page * per
|
75
|
+
stop = (1 + page) * per
|
76
|
+
Recognition::Database.get_transactions bucket, start, stop
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,82 +1,17 @@
|
|
1
|
+
require 'recognition/models/redeemable'
|
2
|
+
|
1
3
|
module Recognition
|
2
4
|
module Models
|
3
5
|
module Voucher
|
4
|
-
|
5
|
-
prefix = Recognition::Parser.parse_code_part(self.class.recognitions[:prefix], self)
|
6
|
-
suffix = Recognition::Parser.parse_code_part(self.class.recognitions[:suffix], self)
|
7
|
-
l = (self.class.recognitions[:code_length] - (prefix.length + suffix.length)) || 10
|
8
|
-
dict = [('a'..'z'),('A'..'Z'),(0..9)].map{|i| i.to_a}.flatten
|
9
|
-
code = (1..l).map{ dict[rand(dict.length)] }.prepend(prefix).append(suffix).join
|
10
|
-
# Prevent code collision at all costs
|
11
|
-
if self.class.to_s.constantize.find_all_by_code(code).any?
|
12
|
-
regenerate_code
|
13
|
-
else
|
14
|
-
self.code = code
|
15
|
-
self
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def redeem recognizable
|
20
|
-
# Make sure we have an amount beforehand
|
21
|
-
if defined? self.amount
|
22
|
-
if self.redeemable? recognizable
|
23
|
-
# Call custom validators
|
24
|
-
if defined? self.class.voucher_validators
|
25
|
-
self.class.voucher_validators.each do |validator|
|
26
|
-
# quit if any validator returned false
|
27
|
-
if send(validator) == false
|
28
|
-
Recognition.log :voucher, "validation error for voucher:#{self.id}"
|
29
|
-
return
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
# If all went well:
|
34
|
-
Recognition::Database.redeem recognizable.id, bucket, 'voucher', self.code, amount.to_i
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def redeemable? recognizable
|
40
|
-
# default: not redeemable
|
41
|
-
pass = false
|
42
|
-
# only check if the voucher did not expire
|
43
|
-
unless expired?
|
44
|
-
# has the voucher ever been redeemed?
|
45
|
-
if transactions.any?
|
46
|
-
# has the voucher ever been redeemed by this user?
|
47
|
-
if get_user_voucher(recognizable.id) != 0
|
48
|
-
pass = false
|
49
|
-
# is the voucher reusable?
|
50
|
-
elsif defined?(self.reusable?) && self.reusable?
|
51
|
-
pass = true
|
52
|
-
end
|
53
|
-
else
|
54
|
-
pass = true
|
55
|
-
end
|
56
|
-
end
|
57
|
-
pass
|
58
|
-
end
|
59
|
-
|
60
|
-
def expired?
|
61
|
-
defined?(self.expires_at) && self.expires_at.present? && self.expires_at < DateTime.now
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
6
|
+
include Recognition::Models::Redeemable
|
65
7
|
|
66
|
-
def
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def get_user_voucher id
|
71
|
-
Recognition::Database.get_counter "user:#{id}", bucket
|
8
|
+
def redeemable? recognizable
|
9
|
+
is_redeemable? recognizable
|
72
10
|
end
|
73
11
|
|
74
|
-
def
|
75
|
-
|
76
|
-
stop = (1 + page) * per
|
77
|
-
Recognition::Database.get_transactions bucket, start, stop
|
12
|
+
def execute_redemption id
|
13
|
+
Recognition::Database.redeem id, bucket, self.class.to_s.downcase, self.code, self.amount.to_i
|
78
14
|
end
|
79
|
-
|
80
15
|
end
|
81
16
|
end
|
82
17
|
end
|
data/lib/recognition/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recognition
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -146,6 +146,7 @@ executables: []
|
|
146
146
|
extensions: []
|
147
147
|
extra_rdoc_files: []
|
148
148
|
files:
|
149
|
+
- lib/generators/recognition/gift_generator.rb
|
149
150
|
- lib/generators/recognition/install_generator.rb
|
150
151
|
- lib/generators/recognition/templates/recognition.rb
|
151
152
|
- lib/generators/recognition/templates/recognition.yml
|
@@ -159,6 +160,7 @@ files:
|
|
159
160
|
- lib/recognition/models/gift.rb
|
160
161
|
- lib/recognition/models/recognizable.rb
|
161
162
|
- lib/recognition/models/recognizer.rb
|
163
|
+
- lib/recognition/models/redeemable.rb
|
162
164
|
- lib/recognition/models/voucher.rb
|
163
165
|
- lib/recognition/parser.rb
|
164
166
|
- lib/recognition/rails/engine.rb
|
@@ -183,7 +185,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
185
|
version: '0'
|
184
186
|
segments:
|
185
187
|
- 0
|
186
|
-
hash:
|
188
|
+
hash: 2026242214967045348
|
187
189
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
190
|
none: false
|
189
191
|
requirements:
|
@@ -192,7 +194,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
192
194
|
version: '0'
|
193
195
|
segments:
|
194
196
|
- 0
|
195
|
-
hash:
|
197
|
+
hash: 2026242214967045348
|
196
198
|
requirements: []
|
197
199
|
rubyforge_project:
|
198
200
|
rubygems_version: 1.8.23
|