icentris-rules 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +33 -0
  5. data/app/assets/images/pyr_rules/ui-anim_basic_16x16.gif +0 -0
  6. data/app/assets/javascripts/pyr_rules/rules.js +135 -0
  7. data/app/assets/stylesheets/pyr_rules/rules.css.scss +258 -0
  8. data/app/assets/stylesheets/scaffold.css +57 -0
  9. data/app/controllers/pyr_rules/actions_controller.rb +22 -0
  10. data/app/controllers/pyr_rules/events_controller.rb +17 -0
  11. data/app/controllers/pyr_rules/rules_controller.rb +233 -0
  12. data/app/helpers/pyr_rules/actions_helper.rb +2 -0
  13. data/app/helpers/pyr_rules/events_helper.rb +95 -0
  14. data/app/helpers/pyr_rules/rules_helper.rb +10 -0
  15. data/app/models/pyr_rules.rb +3 -0
  16. data/app/models/pyr_rules/action.rb +116 -0
  17. data/app/models/pyr_rules/rule.rb +201 -0
  18. data/app/rules/pyr_rules/action_handler.rb +94 -0
  19. data/app/rules/pyr_rules/controller_event_emitter.rb +34 -0
  20. data/app/rules/pyr_rules/email_action_handler.rb +6 -0
  21. data/app/rules/pyr_rules/event_concerns.rb +23 -0
  22. data/app/rules/pyr_rules/event_config_loader.rb +97 -0
  23. data/app/rules/pyr_rules/event_subscriber.rb +36 -0
  24. data/app/rules/pyr_rules/model_creation_handler.rb +25 -0
  25. data/app/rules/pyr_rules/model_event_emitter.rb +80 -0
  26. data/app/rules/pyr_rules/rule_context.rb +20 -0
  27. data/app/rules/pyr_rules/rules_config.rb +87 -0
  28. data/app/rules/pyr_rules/rules_engine.rb +38 -0
  29. data/app/rules/pyr_rules/web_request_logger.rb +6 -0
  30. data/app/views/pyr_rules/actions/index.html.erb +12 -0
  31. data/app/views/pyr_rules/events/_sidebar.html.erb +8 -0
  32. data/app/views/pyr_rules/events/index.html.erb +72 -0
  33. data/app/views/pyr_rules/events/show.html.erb +11 -0
  34. data/app/views/pyr_rules/rules/_form.html.erb +28 -0
  35. data/app/views/pyr_rules/rules/_ready_headers.js.erb +11 -0
  36. data/app/views/pyr_rules/rules/_rule_context_field.html.erb +10 -0
  37. data/app/views/pyr_rules/rules/_rules.html.erb +34 -0
  38. data/app/views/pyr_rules/rules/add_action_mapping.js.erb +13 -0
  39. data/app/views/pyr_rules/rules/edit.html.erb +14 -0
  40. data/app/views/pyr_rules/rules/index.html.erb +5 -0
  41. data/app/views/pyr_rules/rules/lookup_sub_properties.js.erb +13 -0
  42. data/app/views/pyr_rules/rules/new.html.erb +11 -0
  43. data/app/views/pyr_rules/rules/remove_action_mapping.js.erb +15 -0
  44. data/app/views/pyr_rules/rules/show.html.erb +98 -0
  45. data/app/views/shared/_action.html.erb +41 -0
  46. data/app/views/shared/_action_field_mapping.html.erb +33 -0
  47. data/app/views/shared/_event.html.erb +21 -0
  48. data/app/views/shared/_rule.html.erb +27 -0
  49. data/config/routes.rb +32 -0
  50. data/config/security.yml +9 -0
  51. data/db/seeds.rb +1 -0
  52. data/lib/pyr_rules.rb +34 -0
  53. data/lib/pyr_rules/engine.rb +72 -0
  54. data/lib/pyr_rules/generators/dummy_generator.rb +27 -0
  55. data/lib/pyr_rules/version.rb +3 -0
  56. data/lib/tasks/pyr_rules_tasks.rake +57 -0
  57. metadata +224 -0
@@ -0,0 +1,57 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ div.field, div.actions {
20
+ margin-bottom: 10px;
21
+ }
22
+
23
+ #notice {
24
+ color: green;
25
+ }
26
+
27
+ .field_with_errors {
28
+ padding: 2px;
29
+ background-color: red;
30
+ display: table;
31
+ }
32
+
33
+ #error_explanation {
34
+ width: 450px;
35
+ border: 2px solid red;
36
+ padding: 7px;
37
+ padding-bottom: 0;
38
+ margin-bottom: 20px;
39
+ background-color: #f0f0f0;
40
+ }
41
+
42
+ #error_explanation h2 {
43
+ text-align: left;
44
+ font-weight: bold;
45
+ padding: 5px 5px 5px 15px;
46
+ font-size: 12px;
47
+ margin: -7px;
48
+ margin-bottom: 0px;
49
+ background-color: #c00;
50
+ color: #fff;
51
+ }
52
+
53
+ #error_explanation ul li {
54
+ font-size: 12px;
55
+ list-style: square;
56
+ }
57
+
@@ -0,0 +1,22 @@
1
+ class PyrRules::ActionsController < ApplicationController
2
+
3
+ def create
4
+ @rule = PyrRules::Rule.find(params[:rule_id])
5
+ @action = @rule.actions.create!(params[:pyr_rules_action])
6
+
7
+ redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@rule, event_id: params[:event_id]) : pyr_rules_rule_url(@rule)), :notice => "Action created!"
8
+ end
9
+
10
+ def destroy
11
+ @rule = PyrRules::Rule.find(params[:rule_id])
12
+ @rule.actions.delete(@rule.actions.find(params[:id]))
13
+
14
+ redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@rule, event_id: params[:event_id]) : pyr_rules_rule_url(@rule)), :notice => "Action deleted!"
15
+ end
16
+
17
+ def index
18
+ @actions_config = PyrRules::ActionHandler.actions_config
19
+ @actions = @actions_config.map{|type,needs| a= PyrRules::Action.new;a.type=type;a}
20
+ end
21
+
22
+ end
@@ -0,0 +1,17 @@
1
+ class PyrRules::EventsController < ApplicationController
2
+ def index
3
+ @events_tree = PyrRules::RulesConfig.events_tree
4
+ respond_to do |format|
5
+ format.html
6
+ end
7
+ end
8
+
9
+ def show
10
+ @event = PyrRules::RulesConfig.event params[:id]
11
+ @pyr_rules_rules = PyrRules::Rule.where(event: @event[:name]).all
12
+ respond_to do |format|
13
+ format.html
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,233 @@
1
+ module PyrRules
2
+ class RulesController < ApplicationController
3
+
4
+ # before_filter :admin_required # If you include Rules, you want this controller SECURE!!!
5
+
6
+ def lookup_events
7
+ r = Regexp.new(".*#{params[:q]}.*", "i")
8
+ list = PyrRules::RulesConfig.events.grep r
9
+ render json: list.first(10).map{|e| {id: e.gsub("::","__") ,value: e}}
10
+ end
11
+
12
+ def add_event
13
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
14
+ event = params[:event].gsub("__","::") rescue nil
15
+ @pyr_rules_rule.events << event unless @pyr_rules_rule.events.index event
16
+ if @pyr_rules_rule.save
17
+ redirect_to :back, notice: "#{event} is a trigger for this rule"
18
+ else
19
+ redirect_to :back, error: "Could not add event: #{event}. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
20
+ end
21
+ end
22
+
23
+ def remove_event
24
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
25
+ event = params[:event].gsub("__","::") rescue nil
26
+ @pyr_rules_rule.events.delete event
27
+ if @pyr_rules_rule.save
28
+ redirect_to :back, notice: "#{event} is no longer a trigger for this rule"
29
+ else
30
+ redirect_to :back, error: "Could not remove event: #{event}. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
31
+ end
32
+ end
33
+
34
+ def lookup_actions
35
+ r = Regexp.new(".*#{params[:q]}.*", "i")
36
+ list = PyrRules::ActionHandler.action_listing.map(&:to_s).grep r
37
+ render json: list.first(10).map{|a| {id: a.gsub("::","__") ,value: a}}
38
+ end
39
+
40
+ def add_action
41
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
42
+ action = params[:action_class].gsub("__","::") rescue nil
43
+ @pyr_rules_rule.actions << PyrRules::Action.new(type: action)
44
+ if @pyr_rules_rule.save
45
+ redirect_to :back, notice: "Added event: #{action}"
46
+ else
47
+ redirect_to :back, error: "Could not add event: #{action}. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
48
+ end
49
+ end
50
+
51
+ def remove_action
52
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
53
+ action_id = params[:action_id] rescue nil
54
+ action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
55
+ action.delete if action
56
+ if @pyr_rules_rule.save
57
+ redirect_to :back, notice: "Action deleted"
58
+ else
59
+ redirect_to :back, error: "Could not remove action. Suggest you check the logs and maybe this will help, too: #{@pyr_rules_rule.errors}"
60
+ end
61
+
62
+ end
63
+
64
+ def lookup_sub_properties
65
+ @rule = PyrRules::Rule.find(params[:rule_id])
66
+ @div_id = request[:div_id]
67
+ @path = params[:path]
68
+ @ctx = @rule.lookup_path(@path)
69
+ respond_to do |format|
70
+ format.js {}
71
+ format.json { render json: @ctx }
72
+ end
73
+
74
+
75
+ end
76
+
77
+ def add_action_mapping
78
+ PyrRules::Action.add_mapping_type_equivalency(:messaging_user, [:user, :tree_user, :contact])
79
+ PyrRules::Action.add_mapping_type_equivalency(:object, [:user, :messaging_user, :contact, :string])
80
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
81
+ action_id = params[:action_id]
82
+ rule_field = params[:rule_field]
83
+ action_field = params[:action_field]
84
+ @action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
85
+ @was_mapped = @action.context_mapping[action_field]
86
+ @action_field_name = action_field.split(":").first
87
+ @action_field_type = action_field.split(":").last
88
+ if @action_field_type == :class_lookup
89
+ klazz = rule_field.constantize
90
+ @action.context_mapping[action_field] = rule_field
91
+ @pyr_rules_rule.save
92
+ else
93
+ @rule_field_name = rule_field.split(":").first
94
+ rule_type = rule_field.split(":").last
95
+ if PyrRules::Action.check_mapping_type?(@action_field_type, rule_type)
96
+ @action.context_mapping[action_field] = rule_field
97
+ @pyr_rules_rule.save
98
+ else
99
+ @error = "Illegal field type mapping from #{rule_type} to #{@action_field_type}"
100
+ end
101
+ end
102
+ respond_to do |format|
103
+ format.html { redirect_to pyr_rules_rule_path(@pyr_rules_rule) }
104
+ format.js {}
105
+ end
106
+ end
107
+
108
+
109
+ def remove_action_mapping
110
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
111
+ action_id = params[:action_id]
112
+ action_field = params[:action_field]
113
+ @action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
114
+ @action_field_name = action_field.split(":").first
115
+ @action_field_type = action_field.split(":").last
116
+ mapped_from = @action.context_mapping[action_field]
117
+ if mapped_from
118
+ @action.context_mapping[action_field] = nil
119
+ @rule_field_name = mapped_from.split(":").first
120
+ @rule_field_type = mapped_from.split(":").last
121
+ @message = "Removed field mapping for #{@action_field_name}"
122
+ else
123
+ @message = "#{action_field} was not mapped"
124
+ end
125
+ @pyr_rules_rule.save
126
+ respond_to do |format|
127
+ format.html { redirect_to pyr_rules_rule_path(@pyr_rules_rule) }
128
+ format.js {}
129
+ end
130
+ end
131
+
132
+ def reload_rules_engine
133
+ c = PyrRules::RulesEngine.reload_configuration
134
+ notice = "Loaded #{c[:events].try(:size) || '0'} Events and #{c[:actions].try(:size) || '0'} Actions "
135
+ redirect_to :back, notice: notice
136
+ end
137
+
138
+ # GET /pyr_rules/rules
139
+ # GET /pyr_rules/rules.json
140
+ def index
141
+ @pyr_rules_rules = params[:event_id].presence ? PyrRules::Rule.where(event: params[:event_id]).all : PyrRules::Rule.all
142
+
143
+ respond_to do |format|
144
+ format.html # index.html.erb
145
+ format.json { render json: @pyr_rules_rules }
146
+ end
147
+ end
148
+
149
+ # GET /pyr_rules/rules/1
150
+ # GET /pyr_rules/rules/1.json
151
+ def show
152
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
153
+
154
+ respond_to do |format|
155
+ format.html # show.html.erb
156
+ format.json { render json: @pyr_rules_rule }
157
+ end
158
+ end
159
+
160
+ # GET /pyr_rules/rules/new
161
+ # GET /pyr_rules/rules/new.json
162
+ def new
163
+ @pyr_rules_rule = PyrRules::Rule.new
164
+ @pyr_rules_rule.event = params[:event_id] if params[:event_id]
165
+
166
+ respond_to do |format|
167
+ format.html # new.html.erb
168
+ format.json { render json: @pyr_rules_rule }
169
+ end
170
+ end
171
+
172
+ # GET /pyr_rules/rules/1/edit
173
+ def edit
174
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
175
+ end
176
+
177
+ # POST /pyr_rules/rules
178
+ # POST /pyr_rules/rules.json
179
+ def create
180
+ @pyr_rules_rule = PyrRules::Rule.new(params[:pyr_rules_rule])
181
+
182
+ respond_to do |format|
183
+ if @pyr_rules_rule.save
184
+ format.html { redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@pyr_rules_rule, event_id: params[:event_id]) : pyr_rules_rule_url(@pyr_rules_rule)), notice: 'Rule was successfully created.' }
185
+ format.json { render json: @pyr_rules_rule, status: :created, location: @pyr_rules_rule }
186
+ else
187
+ format.html { render action: "new" }
188
+ format.json { render json: @pyr_rules_rule.errors, status: :unprocessable_entity }
189
+ end
190
+ end
191
+ end
192
+
193
+ # PUT /pyr_rules/rules/1
194
+ # PUT /pyr_rules/rules/1.json
195
+ def update
196
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
197
+ # {"action"=>{"522e0313a4c6b2154c000001"=>{"template"=>{"name"=>"asdf"}}}}
198
+ action_update = params[:pyr_rules_rule].delete(:action) rescue nil
199
+ if action_update
200
+ action_id = action_update.keys.first
201
+ action = @pyr_rules_rule.actions.detect{|a| a.id.to_s == action_id}
202
+ puts "Updating Rule #{@pyr_rules_rule.name}- Action #{action.class}"
203
+ template_name = action_update.values.first[:template].keys.first
204
+ template_value = action_update.values.first[:template].values.first
205
+ puts "TemplateName[#{template_name}] TemplateValue[#{template_value}]"
206
+ action.template[template_name] = template_value
207
+ @pyr_rules_rule.save!
208
+ end
209
+ respond_to do |format|
210
+ if @pyr_rules_rule.update_attributes(params[:pyr_rules_rule])
211
+ format.html { redirect_to (params[:event_id].presence ? pyr_rules_event_rule_url(@pyr_rules_rule, event_id: params[:event_id]) : pyr_rules_rule_url(@pyr_rules_rule)), notice: 'Rule was successfully updated.' }
212
+ format.json { head :no_content }
213
+ else
214
+ format.html { render action: "edit" }
215
+ format.json { render json: @pyr_rules_rule.errors, status: :unprocessable_entity }
216
+ end
217
+ end
218
+ end
219
+
220
+ # DELETE /pyr_rules/rules/1
221
+ # DELETE /pyr_rules/rules/1.json
222
+ def destroy
223
+ @pyr_rules_rule = PyrRules::Rule.find(params[:id])
224
+ @pyr_rules_rule.destroy
225
+
226
+ respond_to do |format|
227
+ format.html { redirect_to (params[:event_id].presence ? pyr_rules_event_rules_url(event_id: params[:event_id]) : pyr_rules_rules_url) }
228
+ format.json { head :no_content }
229
+ end
230
+ end
231
+
232
+ end
233
+ end
@@ -0,0 +1,2 @@
1
+ module PyrRules::ActionsHelper
2
+ end
@@ -0,0 +1,95 @@
1
+ # :model_events=>
2
+ # {"PyrCommunity"=>
3
+ # {"Blog"=>
4
+ # {:context=>
5
+ # {"id"=>{:type=>:integer},
6
+ # "title"=>{:type=>:string},
7
+ # "author_id"=>{:type=>:integer},
8
+ # "disqus_shortname"=>{:type=>:string},
9
+ # "background_tile"=>{:type=>:boolean},
10
+ # "background_blur"=>{:type=>:integer},
11
+ # "footer"=>{:type=>:text},
12
+ # "description"=>{:type=>:text},
13
+ # "twitter"=>{:type=>:string},
14
+ # "google_analytics"=>{:type=>:string},
15
+ # "background_uid"=>{:type=>:string},
16
+ # "logo_uid"=>{:type=>:string},
17
+ # "created_at"=>{:type=>:datetime},
18
+ # "updated_at"=>{:type=>:datetime}},
19
+ # :actions=>[:create, :update, :delete]}
20
+ # }
21
+ # },
22
+ # "PyrCore"=>
23
+ # {"Lead"=>
24
+ # {:context=>
25
+ # {"id"=>{:type=>:integer},
26
+ # "first_name"=>{:type=>:string},
27
+ # "last_name"=>{:type=>:string},
28
+ # "email"=>{:type=>:string},
29
+ # "phone"=>{:type=>:string},
30
+ # "lead_group"=>{:type=>:string},
31
+ # "comments"=>{:type=>:text},
32
+ # "user_id"=>{:type=>:integer},
33
+ # "created_at"=>{:type=>:datetime},
34
+ # "updated_at"=>{:type=>:datetime}},
35
+ # :actions=>[:create, :update, :delete]}}}}
36
+
37
+
38
+
39
+ module PyrRules::EventsHelper
40
+
41
+
42
+ def render_tree(events_tree)
43
+ stack = []
44
+ content_tag :div, id: "events_tree" do
45
+ body = ""
46
+ events_tree.each do |event_type, sub_events|
47
+ body += _render_and_recurse(event_type, sub_events, stack) + "\n"
48
+ end
49
+ body.html_safe
50
+ end
51
+ end
52
+
53
+
54
+ def _render_and_recurse(key,children,stack)
55
+ return "" if key.blank? # escape - don't render context variables
56
+ body = ""
57
+ if key == :actions # render each action as a leaf
58
+ children.each do |action|
59
+ body += _render_action_leaf(action, stack)
60
+ end
61
+ elsif key == :context
62
+ body = content_tag :div, class: "collapse-group", style:"block:inline;margin-left:30px;padding:5px;" do
63
+ content_tag :div, id:"#{stack.join('_')}_context", class: "collapse", style: "block:inline;padding:5px;min-height:30px;" do
64
+ context = children.collect{|k,v| "<b>#{k}</b> (<i>#{v}</i>)"}.join("<br/>")
65
+ inner_body = "<a class='btn btn-mini' data-toggle='collapse' data-target='##{stack.join('_')}_context'>context</a>".html_safe
66
+ inner_body += "<div class='collapse-group'>#{context}</div>".html_safe
67
+ inner_body += "<div style='clear:both;'></div>".html_safe
68
+ end
69
+ end
70
+ else
71
+ stack.push key
72
+ body += content_tag :div, class: "collapse-group", style: "margin-left:30px;position:relative;" do
73
+ content_tag :div, id:"#{stack.join('_')}", class: "collapse", style: "padding:5px;min-height:30px;" do
74
+ inner_body = "<a class='btn btn-mini' data-toggle='collapse' data-target='##{stack.join('_')}'>+</a><span style='font-weight:bold;'>#{key.to_s.titleize}</span>"
75
+ children.each do |child_key, grandkids|
76
+ #inner_body += "&nbsp;" * stack.size
77
+ inner_body += _render_and_recurse(child_key, grandkids, stack) + "\n"
78
+ end
79
+ inner_body.html_safe
80
+ end
81
+ end
82
+ stack.pop
83
+ end
84
+ body.html_safe
85
+ end
86
+
87
+ def _render_action_leaf(action_name, stack)
88
+ name = "#{stack.join('::')}_#{action_name}"
89
+ content_tag :div, id: name, style:"margin-left:30px;padding:5px;" do
90
+ content_tag :input, name: name, type: "checkbox" do
91
+ "<span style='margin-left:10px;'>#{action_name.to_s}</span>".html_safe
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,10 @@
1
+ module PyrRules::RulesHelper
2
+
3
+ # Don't drill into these types
4
+ @@dont_drill_types = [:boolean, :datetime, :integer, :messaging_user, :string, :text]
5
+
6
+ def drillable_rule_type?(check_type)
7
+ !@@dont_drill_types.index(check_type)
8
+ end
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ module PyrRules
2
+
3
+ end