recognition 0.3.8 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +4 -3
- data/lib/recognition.rb +5 -2
- data/lib/recognition/controllers/recognizer.rb +13 -0
- data/lib/recognition/database.rb +19 -99
- data/lib/recognition/extensions/action_controller.rb +21 -0
- data/lib/recognition/extensions/active_record.rb +72 -0
- data/lib/recognition/logger.rb +22 -0
- data/lib/recognition/{activerecord/voucher.rb → models/gift.rb} +16 -13
- data/lib/recognition/models/recognizable.rb +31 -0
- data/lib/recognition/{activerecord/model.rb → models/recognizer.rb} +2 -2
- data/lib/recognition/models/voucher.rb +82 -0
- data/lib/recognition/parser.rb +62 -0
- data/lib/recognition/rails/engine.rb +12 -0
- data/lib/recognition/rails/railtie.rb +16 -0
- data/lib/recognition/version.rb +1 -1
- metadata +15 -13
- data/lib/recognition/action_controller_extension.rb +0 -31
- data/lib/recognition/active_record_extension.rb +0 -72
- data/lib/recognition/activerecord/recognizable.rb +0 -26
- data/lib/recognition/condition.rb +0 -12
- data/lib/recognition/engine.rb +0 -10
- data/lib/recognition/railtie.rb +0 -21
- data/lib/recognition/transaction.rb +0 -11
data/README.md
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
# Recognition
|
2
|
+
[![Build Status](https://travis-ci.org/rayasocialmedia/recognition.png?branch=master)](https://travis-ci.org/rayasocialmedia/recognition)
|
2
3
|
|
3
4
|
A fully-fledged reward system for Rails 3.1+.
|
4
5
|
|
5
6
|
## Features
|
6
7
|
|
7
|
-
* Reward users with points for any model method or
|
8
|
+
* Reward users with points for any model method, ActiveRecord crud or even controller methods.
|
8
9
|
* Create vouchers that users can redeem for points.
|
9
10
|
|
10
11
|
## Links
|
11
12
|
|
12
13
|
* [Installation](#Installation)
|
13
|
-
* [Usage](#
|
14
|
-
* [Examples](#
|
14
|
+
* [Usage](#usage)
|
15
|
+
* [Examples](#example)
|
15
16
|
* [Wiki](https://github.com/rayasocialmedia/recognition/wiki)
|
16
17
|
* [Code Documentation](http://rubydoc.info/gems/recognition/frames)
|
17
18
|
* [Changelog](https://raw.github.com/rayasocialmedia/recognition/master/CHANGELOG.txt)
|
data/lib/recognition.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
require "recognition/engine"
|
2
1
|
require "recognition/version"
|
3
|
-
require "recognition/
|
2
|
+
require "recognition/logger"
|
3
|
+
require "recognition/rails/engine"
|
4
|
+
require "recognition/rails/railtie"
|
4
5
|
require "redis"
|
5
6
|
|
6
7
|
module Recognition
|
8
|
+
extend Recognition::Logger
|
9
|
+
|
7
10
|
mattr_accessor :redis
|
8
11
|
# Redis Db connection parameters
|
9
12
|
@@redis = 'localhost:6378'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Controllers
|
3
|
+
module Recognizer
|
4
|
+
def recognize_actions
|
5
|
+
action = params[:action].to_sym
|
6
|
+
self.class.recognitions[action][:proc_params] = params
|
7
|
+
if self.class.recognitions.keys.include? action
|
8
|
+
Recognition::Database.update_points self, action, self.class.recognitions[action]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/recognition/database.rb
CHANGED
@@ -1,98 +1,54 @@
|
|
1
|
-
require
|
1
|
+
require 'recognition/parser'
|
2
2
|
|
3
3
|
module Recognition
|
4
4
|
# Handle all Transactions and logging to Redis
|
5
5
|
module Database
|
6
6
|
def self.log id, amount, bucket, code = nil
|
7
7
|
hash = Time.now.to_f.to_s
|
8
|
+
Recognition.log :transaction, "hash:'#{hash}' user:'#{id}' amount:'#{amount}' bucket:'#{bucket}'"
|
8
9
|
Recognition.backend.multi do
|
9
10
|
Recognition.backend.hincrby "recognition:user:#{ id }:counters", 'points', amount
|
10
11
|
Recognition.backend.hincrby "recognition:user:#{ id }:counters", bucket, amount
|
11
12
|
Recognition.backend.zadd "recognition:user:#{ id }:transactions", hash, { hash: hash, amount: amount, bucket: bucket, datetime: DateTime.now.to_s }.to_json
|
12
13
|
Recognition.backend.zadd 'recognition:transactions', hash, { hash: hash, id: id, amount: amount, bucket: bucket, datetime: DateTime.now.to_s }.to_json
|
13
14
|
unless code.nil?
|
14
|
-
Recognition.backend.zadd "recognition:
|
15
|
+
Recognition.backend.zadd "recognition:#{ code[:type] }:#{ code[:code] }:transactions", hash, { hash: hash, id: id, bucket: bucket, datetime: DateTime.now.to_s }.to_json
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
20
|
def self.get key
|
20
|
-
Recognition.backend.get key
|
21
|
+
Recognition.backend.get "recognition:#{key}"
|
21
22
|
end
|
22
23
|
|
23
|
-
def self.
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.get_user_counter id, counter
|
28
|
-
counter = Recognition.backend.hget("recognition:user:#{ id }:counters", counter)
|
29
|
-
counter.to_i
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.get_user_transactions id, page = 0, per = 20
|
33
|
-
start = page * per
|
34
|
-
stop = (1 + page) * per
|
35
|
-
keypart = "user:#{ id }"
|
36
|
-
self.get_transactions keypart, start, stop
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.get_voucher_transactions code, page = 0, per = 20
|
40
|
-
start = page * per
|
41
|
-
stop = (1 + page) * per
|
42
|
-
keypart = "voucher:#{ code }"
|
43
|
-
self.get_transactions keypart, start, stop
|
24
|
+
def self.get_counter hash, key
|
25
|
+
Recognition.backend.hget("recognition:#{hash}", key).to_i
|
44
26
|
end
|
45
27
|
|
46
28
|
def self.update_points object, action, condition
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
bucket = condition[:bucket]
|
51
|
-
end
|
52
|
-
user = parse_user(object, condition)
|
29
|
+
Recognition.log 'foo', condition.to_s
|
30
|
+
condition[:bucket] ||= "#{ object.class.to_s.camelize }:#{ action }"
|
31
|
+
user = Recognition::Parser.parse_recognizable(object, condition[:recognizable], condition[:proc_params])
|
53
32
|
if condition[:amount].nil? && condition[:gain].nil? && condition[:loss].nil?
|
33
|
+
Recognition.log 'validation', "Unable to determine points: no 'amount', 'gain' or 'loss' specified"
|
54
34
|
false
|
55
35
|
else
|
56
|
-
total = parse_amount(condition[:amount], object) + parse_amount(condition[:gain], object) - parse_amount(condition[:loss], object)
|
57
|
-
ground_total = user.recognition_counter(bucket) + total
|
36
|
+
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])
|
37
|
+
ground_total = user.recognition_counter(condition[:bucket]) + total
|
58
38
|
if condition[:maximum].nil? || ground_total <= condition[:maximum]
|
59
|
-
|
39
|
+
log(user.id, total.to_i, condition[:bucket])
|
40
|
+
else
|
41
|
+
Recognition.log 'validation', "Unable to add points: bucket maximum reached for bucket '#{condition[:bucket]}'"
|
60
42
|
end
|
61
43
|
end
|
62
44
|
end
|
63
45
|
|
64
|
-
def self.
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
def self.get_user_voucher id, code
|
70
|
-
bucket = "Voucher:redeem##{ code }"
|
71
|
-
Database.get_user_counter id, bucket
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.parse_voucher_part part, object
|
75
|
-
case part.class.to_s
|
76
|
-
when 'String'
|
77
|
-
value = part
|
78
|
-
when 'Integer'
|
79
|
-
value = part.to_s
|
80
|
-
when 'Fixnum'
|
81
|
-
value = part.to_s
|
82
|
-
when 'Symbol'
|
83
|
-
value = object.send(part).to_s
|
84
|
-
when 'Proc'
|
85
|
-
value = part.call(object).to_s
|
86
|
-
when 'NilClass'
|
87
|
-
# Do not complain about nil amounts
|
88
|
-
else
|
89
|
-
raise ArgumentError, "type mismatch for voucher part: expecting 'Integer', 'Fixnum', 'Symbol' or 'Proc' but got '#{ amount.class.to_s }' instead."
|
90
|
-
end
|
91
|
-
value || ''
|
46
|
+
def self.redeem id, bucket, type, code, value
|
47
|
+
certificate = { type: type, code: code }
|
48
|
+
Recognition.log type, "redeeming #{type}:#{code} for user: #{id}"
|
49
|
+
log id, value, bucket, certificate
|
92
50
|
end
|
93
51
|
|
94
|
-
private
|
95
|
-
|
96
52
|
def self.get_transactions keypart, start, stop
|
97
53
|
transactions = []
|
98
54
|
range = Recognition.backend.zrange "recognition:#{ keypart }:transactions", start, stop
|
@@ -101,41 +57,5 @@ module Recognition
|
|
101
57
|
end
|
102
58
|
transactions
|
103
59
|
end
|
104
|
-
|
105
|
-
def self.parse_user object, condition
|
106
|
-
if condition[:recognizable].nil?
|
107
|
-
user = object
|
108
|
-
else
|
109
|
-
case condition[:recognizable].class.to_s
|
110
|
-
when 'Symbol'
|
111
|
-
user = object.send(condition[:recognizable])
|
112
|
-
when 'String'
|
113
|
-
user = object.send(condition[:recognizable].to_sym)
|
114
|
-
when 'Proc'
|
115
|
-
user = object.call(condition[:proc_params])
|
116
|
-
else
|
117
|
-
user = condition[:recognizable]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
user
|
121
|
-
end
|
122
|
-
|
123
|
-
def self.parse_amount amount, object
|
124
|
-
case amount.class.to_s
|
125
|
-
when 'Integer'
|
126
|
-
value = amount
|
127
|
-
when 'Fixnum'
|
128
|
-
value = amount
|
129
|
-
when 'Symbol'
|
130
|
-
value = object.send(amount)
|
131
|
-
when 'Proc'
|
132
|
-
value = amount.call(object)
|
133
|
-
when 'NilClass'
|
134
|
-
# Do not complain about nil amounts
|
135
|
-
else
|
136
|
-
raise ArgumentError, "type mismatch for amount: expecting 'Integer', 'Fixnum', 'Symbol' or 'Proc' but got '#{ amount.class.to_s }' instead."
|
137
|
-
end
|
138
|
-
value || 0
|
139
|
-
end
|
140
60
|
end
|
141
61
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Extensions
|
3
|
+
# Extending ActionController
|
4
|
+
module ActionController
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.class_attribute :recognitions
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def recognize recognizable, condition
|
12
|
+
require "recognition/controllers/recognizer"
|
13
|
+
include Recognition::Controllers::Recognizer
|
14
|
+
self.recognitions ||= {}
|
15
|
+
self.recognitions[condition[:for]] = { recognizable: recognizable, amount: condition[:amount], gain: condition[:gain], loss: condition[:loss], maximum: condition[:maximum] }
|
16
|
+
after_filter :recognize_actions
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Extensions
|
3
|
+
module ActiveRecord
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
base.class_attribute :recognitions
|
7
|
+
base.class_attribute :recognizable
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# to be called from user model
|
12
|
+
def acts_as_recognizable options = {}
|
13
|
+
require "recognition/models/recognizable"
|
14
|
+
include Recognition::Models::Recognizable
|
15
|
+
self.recognizable = true
|
16
|
+
self.recognitions ||= {}
|
17
|
+
self.recognitions[:initial] = {
|
18
|
+
amount: options[:initial]
|
19
|
+
}
|
20
|
+
after_save :add_initial_points
|
21
|
+
end
|
22
|
+
|
23
|
+
# to be called from other models
|
24
|
+
def recognize recognizable, condition
|
25
|
+
require "recognition/models/recognizer"
|
26
|
+
include Recognition::Models::Recognizer
|
27
|
+
self.recognitions ||= {}
|
28
|
+
self.recognitions[condition[:for]] = {
|
29
|
+
recognizable: recognizable,
|
30
|
+
bucket: condition[:group],
|
31
|
+
gain: condition[:gain],
|
32
|
+
loss: condition[:loss],
|
33
|
+
maximum: condition[:maximum]
|
34
|
+
}
|
35
|
+
# Due to the lack of ActiveRecord before_filter,
|
36
|
+
# we will have to alias the original method in order to intercept
|
37
|
+
if [:create, :update, :destroy].include? condition[:for]
|
38
|
+
include ActiveModel::Dirty
|
39
|
+
else
|
40
|
+
method = condition[:for]
|
41
|
+
define_method "#{method}_with_recognition" do |*args|
|
42
|
+
if self.send("#{method}_without_recognition", *args)
|
43
|
+
Recognition::Database.update_points self, condition[:for], self.class.recognitions[condition[:for]]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
alias_method_chain method, 'recognition'
|
47
|
+
end
|
48
|
+
# For actions that can be intercepted using ActiveRecord callbacks
|
49
|
+
before_destroy :recognize_destroying
|
50
|
+
after_save :recognize_updating
|
51
|
+
# We use after_save for creation to make sure all associations
|
52
|
+
# have been persisted
|
53
|
+
after_save :recognize_creating
|
54
|
+
end
|
55
|
+
|
56
|
+
# to be called from user-model
|
57
|
+
def acts_as_voucher options = {}
|
58
|
+
require "recognition/models/voucher"
|
59
|
+
include Recognition::Models::Voucher
|
60
|
+
self.recognitions = options
|
61
|
+
cattr_accessor :voucher_validators
|
62
|
+
def self.validates_voucher_redmeption validators
|
63
|
+
self.voucher_validators ||= []
|
64
|
+
self.voucher_validators << validators
|
65
|
+
self.voucher_validators.flatten!
|
66
|
+
end
|
67
|
+
before_create :regenerate_code
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Recognition
|
4
|
+
module Logger
|
5
|
+
def log key, message
|
6
|
+
logger.info("[recognition] [#{key}] #{message}") if logging?
|
7
|
+
end
|
8
|
+
|
9
|
+
def logger #:nodoc:
|
10
|
+
@logger ||= ::Logger.new(STDOUT)
|
11
|
+
end
|
12
|
+
|
13
|
+
def logger=(logger)
|
14
|
+
@logger = logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def logging? #:nodoc:
|
18
|
+
# TODO: Add an option to toggle logging
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Recognition
|
2
|
-
module
|
3
|
-
module
|
2
|
+
module Models
|
3
|
+
module Gift
|
4
4
|
def regenerate_code
|
5
|
-
prefix = Recognition::Database.
|
6
|
-
suffix = Recognition::Database.
|
5
|
+
prefix = Recognition::Database.parse_code_part(self.class.recognitions[:prefix], self)
|
6
|
+
suffix = Recognition::Database.parse_code_part(self.class.recognitions[:suffix], self)
|
7
7
|
l = (self.class.recognitions[:code_length] - (prefix.length + suffix.length)) || 10
|
8
8
|
dict = [('a'..'z'),('A'..'Z'),(0..9)].map{|i| i.to_a}.flatten
|
9
9
|
code = (1..l).map{ dict[rand(dict.length)] }.prepend(prefix).append(suffix).join
|
@@ -21,14 +21,14 @@ module Recognition
|
|
21
21
|
if defined? self.amount
|
22
22
|
if self.redeemable? recognizable
|
23
23
|
# Call custom validators
|
24
|
-
if defined? self.class.
|
25
|
-
self.class.
|
24
|
+
if defined? self.class.gift_validators
|
25
|
+
self.class.gift_validators.each do |validator|
|
26
26
|
# quit if any validator returned false
|
27
27
|
return if send(validator) == false
|
28
28
|
end
|
29
29
|
end
|
30
30
|
# If all went well:
|
31
|
-
Database.
|
31
|
+
Database.redeem_gift recognizable.id, self.code, self.amount
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -36,14 +36,14 @@ module Recognition
|
|
36
36
|
def redeemable? recognizable
|
37
37
|
# default: not redeemable
|
38
38
|
pass = false
|
39
|
-
# only check if the
|
39
|
+
# only check if the gift did not expire
|
40
40
|
unless expired?
|
41
|
-
# has the
|
42
|
-
if Database.
|
43
|
-
# has the
|
44
|
-
if Database.
|
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
45
|
pass = false
|
46
|
-
# is the
|
46
|
+
# is the gift reusable?
|
47
47
|
elsif defined?(self.reusable?) && self.reusable?
|
48
48
|
pass = true
|
49
49
|
end
|
@@ -57,6 +57,9 @@ module Recognition
|
|
57
57
|
def expired?
|
58
58
|
defined?(self.expires_at) && self.expires_at.present? && self.expires_at < DateTime.now
|
59
59
|
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
60
63
|
end
|
61
64
|
end
|
62
65
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Models
|
3
|
+
module Recognizable
|
4
|
+
# Determine user current balance of points
|
5
|
+
def points
|
6
|
+
recognition_counter 'points'
|
7
|
+
end
|
8
|
+
|
9
|
+
def recognition_counter bucket
|
10
|
+
Recognition::Database.get_counter "user:#{ self.id }:counters", bucket
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_initial_points
|
14
|
+
amount = self.class.recognitions[:initial][:amount]
|
15
|
+
update_points amount, :initial
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_points amount, bucket
|
19
|
+
require 'recognition/database'
|
20
|
+
Recognition::Database.log(self.id, amount.to_i, bucket)
|
21
|
+
end
|
22
|
+
|
23
|
+
def transactions page = 0, per = 20
|
24
|
+
start = page * per
|
25
|
+
stop = (1 + page) * per
|
26
|
+
keypart = "user:#{ self.id }"
|
27
|
+
Recognition::Database.get_transactions keypart, start, stop
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Recognition
|
2
|
-
module
|
3
|
-
module
|
2
|
+
module Models
|
3
|
+
module Recognizer
|
4
4
|
def recognize_creating
|
5
5
|
if self.id_changed? # Unless we are creating
|
6
6
|
Database.update_points self, :create, self.class.recognitions[:create] unless self.class.recognitions[:create].nil?
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Models
|
3
|
+
module Voucher
|
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 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
|
65
|
+
|
66
|
+
def bucket
|
67
|
+
"voucher:#{ self.code }"
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_user_voucher id
|
71
|
+
Recognition::Database.get_counter "user:#{id}", bucket
|
72
|
+
end
|
73
|
+
|
74
|
+
def transactions page = 0, per = 20
|
75
|
+
start = page * per
|
76
|
+
stop = (1 + page) * per
|
77
|
+
Recognition::Database.get_transactions bucket, start, stop
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Parser
|
3
|
+
def self.parse_recognizable object, recognizable, proc_params = nil
|
4
|
+
if recognizable.nil?
|
5
|
+
user = object
|
6
|
+
else
|
7
|
+
case recognizable.class.to_s
|
8
|
+
when 'Symbol'
|
9
|
+
user = object.send(recognizable)
|
10
|
+
when 'String'
|
11
|
+
user = object.send(recognizable.to_sym)
|
12
|
+
when 'Proc'
|
13
|
+
params = proc_params || object
|
14
|
+
user = recognizable.call(params)
|
15
|
+
else
|
16
|
+
user = recognizable
|
17
|
+
end
|
18
|
+
end
|
19
|
+
user
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.parse_amount amount, object, proc_params = nil
|
23
|
+
case amount.class.to_s
|
24
|
+
when 'Integer'
|
25
|
+
value = amount
|
26
|
+
when 'Fixnum'
|
27
|
+
value = amount
|
28
|
+
when 'Symbol'
|
29
|
+
value = object.send(amount)
|
30
|
+
when 'Proc'
|
31
|
+
params = proc_params || object
|
32
|
+
value = amount.call(params)
|
33
|
+
when 'NilClass'
|
34
|
+
# Do not complain about nil amounts
|
35
|
+
else
|
36
|
+
raise ArgumentError, "type mismatch for amount: expecting 'Integer', 'Fixnum', 'Symbol' or 'Proc' but got '#{ amount.class.to_s }' instead."
|
37
|
+
end
|
38
|
+
value || 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.parse_code_part part, object
|
42
|
+
case part.class.to_s
|
43
|
+
when 'String'
|
44
|
+
value = part
|
45
|
+
when 'Integer'
|
46
|
+
value = part.to_s
|
47
|
+
when 'Fixnum'
|
48
|
+
value = part.to_s
|
49
|
+
when 'Symbol'
|
50
|
+
value = object.send(part).to_s
|
51
|
+
when 'Proc'
|
52
|
+
value = part.call(object).to_s
|
53
|
+
when 'NilClass'
|
54
|
+
# Do not complain about nil amounts
|
55
|
+
else
|
56
|
+
raise ArgumentError, "type mismatch for voucher part: expecting 'Integer', 'Fixnum', 'Symbol' or 'Proc' but got '#{ amount.class.to_s }' instead."
|
57
|
+
end
|
58
|
+
value || ''
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Recognition
|
2
|
+
module Rails
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
config.generators do |g|
|
5
|
+
g.test_framework :rspec, :fixture => false
|
6
|
+
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
7
|
+
g.assets false
|
8
|
+
g.helper false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "recognition/extensions/active_record"
|
2
|
+
require "recognition/extensions/action_controller"
|
3
|
+
require "rails"
|
4
|
+
|
5
|
+
module Recognition
|
6
|
+
class Railtie < ::Rails::Railtie
|
7
|
+
initializer 'recognition.initialize' do
|
8
|
+
ActiveSupport.on_load(:active_record) do
|
9
|
+
ActiveRecord::Base.send :include, Recognition::Extensions::ActiveRecord
|
10
|
+
end
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
ActionController::Base.send(:include, Recognition::Extensions::ActionController)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
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.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -150,17 +150,19 @@ files:
|
|
150
150
|
- lib/generators/recognition/templates/recognition.rb
|
151
151
|
- lib/generators/recognition/templates/recognition.yml
|
152
152
|
- lib/generators/recognition/voucher_generator.rb
|
153
|
-
- lib/recognition/action_controller_extension.rb
|
154
|
-
- lib/recognition/active_record_extension.rb
|
155
|
-
- lib/recognition/activerecord/model.rb
|
156
|
-
- lib/recognition/activerecord/recognizable.rb
|
157
|
-
- lib/recognition/activerecord/voucher.rb
|
158
153
|
- lib/recognition/backend.rb
|
159
|
-
- lib/recognition/
|
154
|
+
- lib/recognition/controllers/recognizer.rb
|
160
155
|
- lib/recognition/database.rb
|
161
|
-
- lib/recognition/
|
162
|
-
- lib/recognition/
|
163
|
-
- lib/recognition/
|
156
|
+
- lib/recognition/extensions/action_controller.rb
|
157
|
+
- lib/recognition/extensions/active_record.rb
|
158
|
+
- lib/recognition/logger.rb
|
159
|
+
- lib/recognition/models/gift.rb
|
160
|
+
- lib/recognition/models/recognizable.rb
|
161
|
+
- lib/recognition/models/recognizer.rb
|
162
|
+
- lib/recognition/models/voucher.rb
|
163
|
+
- lib/recognition/parser.rb
|
164
|
+
- lib/recognition/rails/engine.rb
|
165
|
+
- lib/recognition/rails/railtie.rb
|
164
166
|
- lib/recognition/version.rb
|
165
167
|
- lib/recognition.rb
|
166
168
|
- lib/tasks/recognition_tasks.rake
|
@@ -181,7 +183,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
181
183
|
version: '0'
|
182
184
|
segments:
|
183
185
|
- 0
|
184
|
-
hash:
|
186
|
+
hash: -4080240542959513995
|
185
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
188
|
none: false
|
187
189
|
requirements:
|
@@ -190,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
192
|
version: '0'
|
191
193
|
segments:
|
192
194
|
- 0
|
193
|
-
hash:
|
195
|
+
hash: -4080240542959513995
|
194
196
|
requirements: []
|
195
197
|
rubyforge_project:
|
196
198
|
rubygems_version: 1.8.23
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require "recognition/database"
|
2
|
-
|
3
|
-
module Recognition
|
4
|
-
# Extending ActiveRecord
|
5
|
-
module ActionControllerExtension
|
6
|
-
def self.included(base)
|
7
|
-
base.extend ClassMethods
|
8
|
-
base.class_attribute :recognitions
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def recognize recognizable, condition
|
13
|
-
include InstanceMethods
|
14
|
-
self.recognitions ||= {}
|
15
|
-
self.recognitions[condition[:for]] = { recognizable: recognizable, amount: condition[:amount], maximum: condition[:maximum] || 0 }
|
16
|
-
after_filter :recognize_actions
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
module InstanceMethods
|
22
|
-
def recognize_actions
|
23
|
-
action = params[:action].to_sym
|
24
|
-
if self.class.recognitions.keys.include? action
|
25
|
-
# update_points current_user.id, action, self.class.recognitions[action][:amount]
|
26
|
-
Database.update_points self, action, self.class.recognitions[action]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require "recognition/database"
|
2
|
-
|
3
|
-
module Recognition
|
4
|
-
module ActiveRecordExtension
|
5
|
-
def self.included(base)
|
6
|
-
base.extend ClassMethods
|
7
|
-
base.class_attribute :recognitions
|
8
|
-
base.class_attribute :recognizable
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
# to be called from user model
|
13
|
-
def acts_as_recognizable options = {}
|
14
|
-
require "recognition/activerecord/recognizable"
|
15
|
-
include Recognition::ActiveRecord::Recognizable
|
16
|
-
self.recognizable = true
|
17
|
-
self.recognitions ||= {}
|
18
|
-
self.recognitions[:initial] = {
|
19
|
-
amount: options[:initial]
|
20
|
-
}
|
21
|
-
after_save :add_initial_points
|
22
|
-
end
|
23
|
-
|
24
|
-
# to be called from other models
|
25
|
-
def recognize recognizable, condition
|
26
|
-
require "recognition/activerecord/model"
|
27
|
-
include Recognition::ActiveRecord::Model
|
28
|
-
self.recognitions ||= {}
|
29
|
-
self.recognitions[condition[:for]] = {
|
30
|
-
recognizable: recognizable,
|
31
|
-
bucket: condition[:group],
|
32
|
-
gain: condition[:gain],
|
33
|
-
loss: condition[:loss],
|
34
|
-
maximum: condition[:maximum]
|
35
|
-
}
|
36
|
-
# Due to the lack of ActiveRecord before_filter,
|
37
|
-
# we will have to alias the original method in order to intercept
|
38
|
-
if [:create, :update, :destroy].include? condition[:for]
|
39
|
-
include ActiveModel::Dirty
|
40
|
-
else
|
41
|
-
method = condition[:for]
|
42
|
-
define_method "#{method}_with_recognition" do |*args|
|
43
|
-
if self.send("#{method}_without_recognition", *args)
|
44
|
-
Database.update_points self, condition[:for], self.class.recognitions[condition[:for]]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
alias_method_chain method, 'recognition'
|
48
|
-
end
|
49
|
-
# For actions that can be intercepted using ActiveRecord callbacks
|
50
|
-
before_destroy :recognize_destroying
|
51
|
-
after_save :recognize_updating
|
52
|
-
# We use after_save for creation to make sure all associations
|
53
|
-
# have been persisted
|
54
|
-
after_save :recognize_creating
|
55
|
-
end
|
56
|
-
|
57
|
-
# to be called from user-model
|
58
|
-
def acts_as_voucher options = {}
|
59
|
-
require "recognition/activerecord/voucher"
|
60
|
-
include Recognition::ActiveRecord::Voucher
|
61
|
-
self.recognitions = options
|
62
|
-
cattr_accessor :voucher_validators
|
63
|
-
def self.validates_voucher_redmeption validators
|
64
|
-
self.voucher_validators ||= []
|
65
|
-
self.voucher_validators << validators
|
66
|
-
self.voucher_validators.flatten!
|
67
|
-
end
|
68
|
-
before_create :regenerate_code
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module Recognition
|
2
|
-
module ActiveRecord
|
3
|
-
module Recognizable
|
4
|
-
# Determine user current balance of points
|
5
|
-
def points
|
6
|
-
Database.get_user_points self.id
|
7
|
-
end
|
8
|
-
|
9
|
-
def recognition_counter bucket
|
10
|
-
Database.get_user_counter self.id, bucket
|
11
|
-
end
|
12
|
-
|
13
|
-
def add_initial_points
|
14
|
-
Database.update_points self, :initial, self.class.recognitions[:initial]
|
15
|
-
end
|
16
|
-
|
17
|
-
def update_points amount, bucket
|
18
|
-
Database.log(self.id, amount.to_i, bucket)
|
19
|
-
end
|
20
|
-
|
21
|
-
def transactions page = 0, per = 20
|
22
|
-
Database.get_user_transactions self.id, page, per
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/recognition/engine.rb
DELETED
data/lib/recognition/railtie.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require "recognition/active_record_extension"
|
2
|
-
require "recognition/action_controller_extension"
|
3
|
-
require "rails"
|
4
|
-
|
5
|
-
module Recognition
|
6
|
-
class Railtie < Rails::Railtie
|
7
|
-
initializer 'recognition.initialize' do
|
8
|
-
ActiveSupport.on_load(:active_record) do
|
9
|
-
ActiveRecord::Base.send :include, ActiveRecordExtension
|
10
|
-
end
|
11
|
-
ActiveSupport.on_load(:action_controller) do
|
12
|
-
ActionController::Base.send(:include, ActionControllerExtension)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
#
|
16
|
-
# initializer 'recognition.database' do
|
17
|
-
# #TODO: use a Rails initializer
|
18
|
-
# $REDIS = Redis.new #(host: 'localhost', port: redis_config[:port])
|
19
|
-
# end
|
20
|
-
end
|
21
|
-
end
|