newbamboo-modmonkey_client 0.0.2
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.
- data/History.txt +4 -0
- data/Manifest.txt +16 -0
- data/PostInstall.txt +7 -0
- data/README.txt +198 -0
- data/VERSION.yml +4 -0
- data/lib/modmonkey_client.rb +20 -0
- data/lib/modmonkey_client/item.rb +175 -0
- data/lib/modmonkey_client/mod_monkey.rb +134 -0
- data/lib/modmonkey_client/moderatables.rb +15 -0
- data/lib/modmonkey_client/profile.rb +82 -0
- data/spec/modmonkey_client/item_controller_spec.rb +21 -0
- data/spec/modmonkey_client/item_model_spec.rb +149 -0
- data/spec/modmonkey_client/moderatables_spec.rb +14 -0
- data/spec/modmonkey_client/profile_controller_spec.rb +19 -0
- data/spec/modmonkey_client/profile_model_spec.rb +20 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/test_comment.rb +17 -0
- data/spec/test_user.rb +3 -0
- metadata +75 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
PostInstall.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
lib/modmonkey_client.rb
|
7
|
+
lib/modmonkey_client/mod_monkey.rb
|
8
|
+
lib/modmonkey_client/profile.rb
|
9
|
+
lib/modmonkey_client/item.rb
|
10
|
+
lib/modmonkey_client/moderatables.rb
|
11
|
+
script/console
|
12
|
+
script/destroy
|
13
|
+
script/generate
|
14
|
+
spec/spec.opts
|
15
|
+
spec/spec_helper.rb
|
16
|
+
tasks/rspec.rake
|
data/PostInstall.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
There is a ruby gem which handles a lot of stuff for you
|
2
|
+
|
3
|
+
General principles
|
4
|
+
---
|
5
|
+
|
6
|
+
items and profiles which have corresponding things on the server
|
7
|
+
|
8
|
+
Models
|
9
|
+
---
|
10
|
+
|
11
|
+
Item
|
12
|
+
---
|
13
|
+
|
14
|
+
database fields
|
15
|
+
|
16
|
+
<pre>
|
17
|
+
class AddImages < ActiveRecord::Migration
|
18
|
+
def self.up
|
19
|
+
create_table :test_images do |t|
|
20
|
+
t.string :photo_file_name
|
21
|
+
t.string :mm_key
|
22
|
+
t.string :mm_approved
|
23
|
+
t.string :mm_id
|
24
|
+
t.string :test_user_id
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.down
|
29
|
+
drop_table :test_images
|
30
|
+
end
|
31
|
+
end
|
32
|
+
</pre>
|
33
|
+
|
34
|
+
Adding moderation to the model
|
35
|
+
|
36
|
+
<pre>
|
37
|
+
class Comment < ActiveRecord::Base
|
38
|
+
extend ModMonkey::Item::ActMethods
|
39
|
+
make_moderatable :content_type=>'text',
|
40
|
+
:profile_info => {
|
41
|
+
:identifier => lambda{|obj| obj.test_user.email},
|
42
|
+
:profile_url => lambda{|obj| SITE_URL+"/test_users/#{obj.test_user.id}"}
|
43
|
+
},
|
44
|
+
:item_url => lambda{|obj| SITE_URL+"/test_comments/#{obj.id}"},
|
45
|
+
:editable_attrs => [:body]
|
46
|
+
|
47
|
+
def mm_content
|
48
|
+
{ :body => self.body }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
</pre>
|
52
|
+
|
53
|
+
optional attrs and methods
|
54
|
+
|
55
|
+
* content_type
|
56
|
+
* mm_content
|
57
|
+
* editable_attrs
|
58
|
+
* item_url
|
59
|
+
* profile_url
|
60
|
+
* asset_url
|
61
|
+
|
62
|
+
Specifying these values can be done via: lambdas, symbols or variables
|
63
|
+
|
64
|
+
|
65
|
+
callbacks created automatically for the following:
|
66
|
+
|
67
|
+
* create
|
68
|
+
* adds item to queue
|
69
|
+
* update
|
70
|
+
* updates item in queue
|
71
|
+
* delete
|
72
|
+
* removes item from queue
|
73
|
+
|
74
|
+
Though these are automatic, it is usually necessary to think about how failure is handled. Section on this in "Maintenance".
|
75
|
+
|
76
|
+
assumptions about moderated content and applying decisions
|
77
|
+
---
|
78
|
+
|
79
|
+
The default behaviour is to switch mm_approved on or off with a modified find. However this could be overridden to destroy the objects completely, or do some other strategy.
|
80
|
+
|
81
|
+
added methods
|
82
|
+
---
|
83
|
+
|
84
|
+
* reject
|
85
|
+
* approve
|
86
|
+
|
87
|
+
usually necessary to apply callbacks to these to cover:
|
88
|
+
|
89
|
+
* cascading
|
90
|
+
* banning user
|
91
|
+
* emailing notifications
|
92
|
+
|
93
|
+
---
|
94
|
+
|
95
|
+
Profile
|
96
|
+
---
|
97
|
+
|
98
|
+
database fields
|
99
|
+
|
100
|
+
<pre>
|
101
|
+
class CreateTestUsers < ActiveRecord::Migration
|
102
|
+
def self.up
|
103
|
+
create_table :test_users do |t|
|
104
|
+
t.string :email
|
105
|
+
t.boolean :banned
|
106
|
+
|
107
|
+
t.timestamps
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.down
|
112
|
+
drop_table :test_users
|
113
|
+
end
|
114
|
+
end
|
115
|
+
</pre>
|
116
|
+
|
117
|
+
Adding moderatble functionality
|
118
|
+
---
|
119
|
+
|
120
|
+
<pre>
|
121
|
+
class User < ActiveRecord::Base
|
122
|
+
extend ModMonkey::Profile::ActMethods
|
123
|
+
make_moderatable
|
124
|
+
end
|
125
|
+
</pre>
|
126
|
+
|
127
|
+
methods called via the options given:
|
128
|
+
|
129
|
+
* ban
|
130
|
+
* unban
|
131
|
+
|
132
|
+
usually necessary to apply callbacks to these to cover:
|
133
|
+
|
134
|
+
* cascading
|
135
|
+
* banning user
|
136
|
+
* emailing notifications
|
137
|
+
|
138
|
+
---
|
139
|
+
|
140
|
+
Controllers
|
141
|
+
---
|
142
|
+
|
143
|
+
SECURITY
|
144
|
+
|
145
|
+
implementation - AOP
|
146
|
+
|
147
|
+
Items
|
148
|
+
---
|
149
|
+
|
150
|
+
<pre>
|
151
|
+
class TestImagesController < ApplicationController
|
152
|
+
extend ModMonkey::ControllerActMethods
|
153
|
+
make_moderatable
|
154
|
+
end
|
155
|
+
</pre>
|
156
|
+
|
157
|
+
mm_update
|
158
|
+
|
159
|
+
update action applies decision etc
|
160
|
+
|
161
|
+
Flags
|
162
|
+
---
|
163
|
+
|
164
|
+
Method which can be posted to to add a flag to the item in the queue. Can have an optional reason, if UI supports this.
|
165
|
+
|
166
|
+
---
|
167
|
+
|
168
|
+
Profile
|
169
|
+
---
|
170
|
+
|
171
|
+
<pre>
|
172
|
+
class TestUsersController < ApplicationController
|
173
|
+
extend ModMonkey::ProfileControllerActMethods
|
174
|
+
make_moderatable
|
175
|
+
end
|
176
|
+
</pre>
|
177
|
+
|
178
|
+
mm\_profile\_update checks permission and calls apply\_mod\_monkey\_params
|
179
|
+
|
180
|
+
all the callbacks for banning etc
|
181
|
+
|
182
|
+
- doesn't do cascading on the users content on this side, but does on the server ?
|
183
|
+
|
184
|
+
---
|
185
|
+
|
186
|
+
Routes
|
187
|
+
---
|
188
|
+
|
189
|
+
items which are moderated need to have a flags resource which can be posted to -
|
190
|
+
often helpful to have a helper in views
|
191
|
+
|
192
|
+
Gotchas
|
193
|
+
---
|
194
|
+
|
195
|
+
* login_required
|
196
|
+
|
197
|
+
Rake tasks
|
198
|
+
---
|
data/VERSION.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
|
2
|
+
$:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rest_client'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'rest-client'
|
9
|
+
require 'rest_client'
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'modmonkey_client/mod_monkey'
|
13
|
+
require 'modmonkey_client/item.rb'
|
14
|
+
require 'modmonkey_client/profile.rb'
|
15
|
+
require 'modmonkey_client/moderatables.rb'
|
16
|
+
# require 'modmonkey_client/hasher.rb'
|
17
|
+
# require 'modmonkey_client/rest_client_extensions.rb'
|
18
|
+
# require 'modmonkey_client/config.rb'
|
19
|
+
|
20
|
+
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module ModMonkey
|
2
|
+
module Item
|
3
|
+
module ActMethods
|
4
|
+
|
5
|
+
attr_accessor :mm_attr_store
|
6
|
+
attr_accessor :editable_attrs
|
7
|
+
attr_accessor :mandatory_keys
|
8
|
+
attr_accessor :optional_keys
|
9
|
+
|
10
|
+
def make_moderatable(options={}, &block)
|
11
|
+
self.mandatory_keys = [:content_type, :profile_info, :item_url]
|
12
|
+
self.optional_keys = [:asset_url, :context_url, :content_description]
|
13
|
+
|
14
|
+
# Process passed in options
|
15
|
+
# These 'dynamic methods' are stored either as a lambda, proc, symbol for method, or ordinary variable
|
16
|
+
validate_keys(options)
|
17
|
+
|
18
|
+
self.editable_attrs = options[:editable_attrs] || []
|
19
|
+
self.mm_attr_store = options.select{|k,v| (mandatory_keys+optional_keys).include? k }
|
20
|
+
|
21
|
+
unless included_modules.include?(Moderatable)
|
22
|
+
before_create :set_default_approval_status
|
23
|
+
after_create :create_mm_item
|
24
|
+
after_update :update_mm_item
|
25
|
+
after_destroy :destroy_mm_item
|
26
|
+
attr_accessor :mm_update
|
27
|
+
named_scope :approved, :conditions => {:mm_approved => true}
|
28
|
+
include Moderatable
|
29
|
+
ModMonkey::Moderatables.add(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_keys(options)
|
34
|
+
unless (options.keys | self.mandatory_keys) == options.keys
|
35
|
+
raise ArgumentError, "make_moderatable needs the following mandatory keys: #{(mandatory_keys).join(', ')}"
|
36
|
+
end
|
37
|
+
if options[:profile_info] &&
|
38
|
+
!options[:profile_info].is_a?(Symbol) &&
|
39
|
+
options[:profile_info][:profile_url].blank?
|
40
|
+
raise ArgumentError, "make_moderatable needs the profile_url to be specified"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def find(*args)
|
45
|
+
with_scope :find=>{:conditions=>"#{self.to_s.tableize}.mm_approved=1"} do
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_unmoderated()
|
51
|
+
find(:all, :conditions => "mm_id is null")
|
52
|
+
end
|
53
|
+
|
54
|
+
def resource_url
|
55
|
+
# File.join(::ModMonkey::Config.api_domain, 'accounts', ::ModMonkey::Config.api_key, "items")
|
56
|
+
File.join(MM_API_DOMAIN, 'accounts', MM_API_KEY, "items")
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_content_description
|
60
|
+
self.to_s.humanize
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
module Moderatable
|
66
|
+
attr_accessor :mm_item
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
# mod monkey
|
71
|
+
def apply_mod_monkey_params( params )
|
72
|
+
apply_decision(params)
|
73
|
+
update_content(params)
|
74
|
+
self.save!
|
75
|
+
end
|
76
|
+
|
77
|
+
# mod monkey callbacks
|
78
|
+
def reject
|
79
|
+
self.mm_approved = false
|
80
|
+
self.save
|
81
|
+
end
|
82
|
+
def approve
|
83
|
+
self.mm_approved = true
|
84
|
+
self.save
|
85
|
+
end
|
86
|
+
|
87
|
+
def flag(params={})
|
88
|
+
flag = Hash.from_xml(RestClient::Resource.new(self.class.resource_url+"/#{self.mm_id}/flags").post(params))
|
89
|
+
end
|
90
|
+
|
91
|
+
def mm_attrs
|
92
|
+
# Evaluate each attribute and return the hash
|
93
|
+
attrs = {}
|
94
|
+
self.class.mm_attr_store.each do |attr_name,value|
|
95
|
+
evaluated_value = evaluate_value(value)
|
96
|
+
attrs[attr_name] = evaluated_value
|
97
|
+
end
|
98
|
+
attrs
|
99
|
+
end
|
100
|
+
|
101
|
+
def evaluate_value(value)
|
102
|
+
if value.respond_to?(:call) then value.call(self)
|
103
|
+
elsif value.is_a?(Symbol) && self.respond_to?(value) then self.send(value)
|
104
|
+
elsif value.is_a?(Hash) then
|
105
|
+
new_hash = {}
|
106
|
+
value.each {|k,v| new_hash[k] = evaluate_value(v)}
|
107
|
+
new_hash
|
108
|
+
else value
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def mm_content
|
113
|
+
raise NotImplementedError, 'the method mm_content needs to be implemented in the including class'
|
114
|
+
end
|
115
|
+
|
116
|
+
def add_to_queue
|
117
|
+
create_mm_item
|
118
|
+
end
|
119
|
+
|
120
|
+
def moderated?
|
121
|
+
!self.mm_id.blank?
|
122
|
+
end
|
123
|
+
|
124
|
+
protected
|
125
|
+
|
126
|
+
def set_default_approval_status
|
127
|
+
self.mm_approved = true
|
128
|
+
end
|
129
|
+
|
130
|
+
# mod monkey
|
131
|
+
def apply_decision(mm_item)
|
132
|
+
case mm_item['decision']
|
133
|
+
when 'rejected'
|
134
|
+
self.reject
|
135
|
+
when 'approved'
|
136
|
+
self.approve
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def update_content(mm_item)
|
141
|
+
evaluate_value(self.class.editable_attrs).each do |attr|
|
142
|
+
self.write_attribute( attr, mm_item[ attr.to_s ] )
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# mod monkey
|
147
|
+
def create_mm_item
|
148
|
+
begin
|
149
|
+
attrs_for_create = {:item => self.mm_attrs.merge(self.mm_content)}
|
150
|
+
self.mm_item = Hash.from_xml(RestClient::Resource.new(self.class.resource_url).post(attrs_for_create))['item']
|
151
|
+
self.mm_id = self.mm_item['id']
|
152
|
+
self.mm_key = self.mm_item['item_key']
|
153
|
+
self.save
|
154
|
+
rescue Exception => e
|
155
|
+
logger.info("#{e.inspect}, backtrace: #{e.backtrace.join("\n")} - #{mm_item.inspect} with #{attrs_for_create.inspect}")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def update_mm_item
|
160
|
+
true
|
161
|
+
end
|
162
|
+
|
163
|
+
def destroy_mm_item
|
164
|
+
RestClient::Resource.new(self.mm_item_url).delete if self.moderated?
|
165
|
+
end
|
166
|
+
|
167
|
+
protected
|
168
|
+
|
169
|
+
def mm_item_url
|
170
|
+
self.class.resource_url + "/#{self.mm_id}"
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
raise %q(Please define the following constants in your environment:
|
2
|
+
MM_API_DOMAIN
|
3
|
+
SITE_URL
|
4
|
+
MM_API_KEY
|
5
|
+
SITE_HOSTNAME
|
6
|
+
) unless (defined?(MM_API_DOMAIN) &&
|
7
|
+
defined?(SITE_URL) &&
|
8
|
+
defined?(MM_API_KEY) &&
|
9
|
+
defined?(SITE_HOSTNAME))
|
10
|
+
|
11
|
+
module ModMonkey
|
12
|
+
|
13
|
+
APPROVAL_STATES = {
|
14
|
+
'APPROVED' => 'approved',
|
15
|
+
'REJECTED' => 'rejected'
|
16
|
+
}
|
17
|
+
|
18
|
+
ITEMS_RESOURCE_URL = File.join(MM_API_DOMAIN, 'accounts', MM_API_KEY, "items")
|
19
|
+
|
20
|
+
module ControllerActMethods
|
21
|
+
def make_moderatable(options={}, &block)
|
22
|
+
unless included_modules.include?(MonkeyController)
|
23
|
+
if defined?(Merb)
|
24
|
+
before :mm_update, :only => [:update]
|
25
|
+
provides :xml, :only => [:update]
|
26
|
+
include MerbMonkeyController
|
27
|
+
else
|
28
|
+
before_filter :mm_update, :only => [:update]
|
29
|
+
include MonkeyController
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module ProfileControllerActMethods
|
36
|
+
def make_moderatable(options={}, &block)
|
37
|
+
unless included_modules.include?(MonkeyProfileController)
|
38
|
+
if defined?(Merb)
|
39
|
+
before :mm_profile_update, :only => [:update]
|
40
|
+
provides :xml, :only => [:update]
|
41
|
+
include MerbMonkeyProfileController
|
42
|
+
else
|
43
|
+
before_filter :mm_profile_update, :only => [:update]
|
44
|
+
include MonkeyProfileController
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
###### RAILS
|
51
|
+
|
52
|
+
module MonkeyProfileController
|
53
|
+
private
|
54
|
+
|
55
|
+
# this method is called before any update actions in your controllers
|
56
|
+
def mm_profile_update
|
57
|
+
if params[:mod_monkey_profile]
|
58
|
+
#@test_user = TestUser.find_by_mm_id(params[:mod_monkey_profile][:id])
|
59
|
+
@test_user = TestUser.find(params[:id])
|
60
|
+
raise ActiveRecord::RecordNotFound if @test_user.nil?
|
61
|
+
@test_user.apply_mod_monkey_params(params[:mod_monkey_profile])
|
62
|
+
render :xml => @test_user.to_xml and return false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module MonkeyController
|
68
|
+
def flag
|
69
|
+
klass = self.controller_name.singularize.camelize.constantize
|
70
|
+
@obj = klass.find(params[:id])
|
71
|
+
# we might want to pass in some more args
|
72
|
+
@obj.flag(params[:flag])
|
73
|
+
redirect_to :back
|
74
|
+
end
|
75
|
+
|
76
|
+
# this method is called before any update actions in your controllers
|
77
|
+
def mm_update
|
78
|
+
if params[:mod_monkey_item]
|
79
|
+
klass = self.controller_name.singularize.camelize.constantize
|
80
|
+
@obj = klass.find_by_mm_id_and_mm_key(params[:mod_monkey_item][:id], params[:mod_monkey_item][:item_key])
|
81
|
+
@obj.apply_mod_monkey_params( params[:mod_monkey_item] )
|
82
|
+
render :xml => @obj.to_xml and return false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
############ MERB STUFF
|
88
|
+
|
89
|
+
module MerbMonkeyProfileController
|
90
|
+
|
91
|
+
def self.included(base)
|
92
|
+
base.show_action(:mm_profile_update)
|
93
|
+
end
|
94
|
+
|
95
|
+
# this method is called before any update actions in your controllers
|
96
|
+
def mm_profile_update
|
97
|
+
if params[:mod_monkey_profile]
|
98
|
+
klass = self.controller_name.singularize.camelize.constantize
|
99
|
+
@obj = klass.find(params[:id])
|
100
|
+
@obj.apply_mod_monkey_params(params[:mod_monkey_profile])
|
101
|
+
render @obj.to_xml and throw :halt
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
module MerbMonkeyController
|
107
|
+
def self.included(base)
|
108
|
+
base.show_action("flag", "mm_update")
|
109
|
+
end
|
110
|
+
|
111
|
+
def mm_update
|
112
|
+
if params[:mod_monkey_item]
|
113
|
+
klass = self.controller_name.singularize.camelize.constantize
|
114
|
+
@obj = klass.find_by_mm_id_and_mm_key(params[:mod_monkey_item][:id], params[:mod_monkey_item][:item_key])
|
115
|
+
@obj.apply_mod_monkey_params( params[:mod_monkey_item] )
|
116
|
+
render @obj.to_xml and throw :halt
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def flag
|
121
|
+
klass = self.controller_name.singularize.camelize.constantize
|
122
|
+
@obj = klass.find(params[:id])
|
123
|
+
# we might want to pass in some more args
|
124
|
+
@obj.flag(params[:flag])
|
125
|
+
if defined?(MerbHasFlash)
|
126
|
+
flash[:notice] = MM_FLAG_NOTICE
|
127
|
+
redirect "/"
|
128
|
+
else
|
129
|
+
redirect "/", :message => {:notice => MM_FLAG_NOTICE}
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module ModMonkey
|
2
|
+
module Profile
|
3
|
+
|
4
|
+
BANNED_STATES = {
|
5
|
+
'BANNED' => 'banned',
|
6
|
+
'UNBANNED' => 'unbanned'
|
7
|
+
}
|
8
|
+
|
9
|
+
module ActMethods
|
10
|
+
|
11
|
+
attr_accessor :mm_attr_store
|
12
|
+
attr_accessor :editable_attrs
|
13
|
+
|
14
|
+
def make_moderatable(options={}, &block)
|
15
|
+
|
16
|
+
# Process passed in options
|
17
|
+
# These 'dynamic methods' are stored either as a lambda, proc, symbol for method, or ordinary variable
|
18
|
+
# mm_attr_keys = [:content_type, :profile_info, :item_url]
|
19
|
+
# raise ArgumentError, "make_moderatable needs the following mandatory keys: #{(mm_attr_keys).join(', ')}" unless (options.keys | mm_attr_keys) == options.keys
|
20
|
+
# self.editable_attrs = options[:editable_attrs] || []
|
21
|
+
# self.mm_attr_store = options.select{|k,v| mm_attr_keys.include? k }
|
22
|
+
#
|
23
|
+
unless included_modules.include?(Moderatable)
|
24
|
+
# before_create :set_default_approval_status
|
25
|
+
# after_create :create_mm_item
|
26
|
+
# after_update :update_mm_item
|
27
|
+
# after_destroy :destroy_mm_item
|
28
|
+
# attr_accessor :mm_update
|
29
|
+
# named_scope :approved, :conditions => {:mm_approved => true}
|
30
|
+
include Moderatable
|
31
|
+
# def self.find(*args)
|
32
|
+
# with_scope :find=>{:conditions=>"#{self.to_s.tableize}.mm_approved=1"} do
|
33
|
+
# super
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
module Moderatable
|
42
|
+
|
43
|
+
# mod monkey
|
44
|
+
def apply_mod_monkey_params( params )
|
45
|
+
apply_decision(params)
|
46
|
+
self.save!
|
47
|
+
end
|
48
|
+
|
49
|
+
# mod monkey callbacks
|
50
|
+
def ban
|
51
|
+
self.mm_banned = true
|
52
|
+
self.save
|
53
|
+
end
|
54
|
+
|
55
|
+
def unban
|
56
|
+
self.mm_banned = false
|
57
|
+
self.save
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# mod monkey
|
63
|
+
def apply_decision(mm_item)
|
64
|
+
case mm_item['status']
|
65
|
+
when BANNED_STATES['BANNED']
|
66
|
+
self.ban
|
67
|
+
when BANNED_STATES['UNBANNED']
|
68
|
+
self.unban
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def update_mm_item
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
def destroy_mm_item
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class ModeratableController < ActionController::Base
|
4
|
+
|
5
|
+
extend ModMonkey::ControllerActMethods
|
6
|
+
make_moderatable
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ModeratableController do
|
11
|
+
|
12
|
+
before :each do
|
13
|
+
@controller = ModeratableController.new
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have an update method" do
|
17
|
+
pending
|
18
|
+
@controller.should be_respond_to('update')
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe TestComment do
|
4
|
+
|
5
|
+
describe "making our model moderatable" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@test_user = TestUser.create!()
|
9
|
+
@default_options = {
|
10
|
+
:content_type => 'text',
|
11
|
+
:profile_info => {
|
12
|
+
:email => "fsdfs@fdsaf.com",
|
13
|
+
:profile_url => "localhost:3000/users/1"
|
14
|
+
},
|
15
|
+
:item_url => '/jello',
|
16
|
+
:editable_attrs => [:body] }
|
17
|
+
end
|
18
|
+
|
19
|
+
[:content_type, :profile_info, :item_url].each do |key|
|
20
|
+
|
21
|
+
it "should require #{key}" do
|
22
|
+
$key = key
|
23
|
+
$default_options = @default_options
|
24
|
+
lambda {
|
25
|
+
class TestComment
|
26
|
+
make_moderatable $default_options.reject{|k,v|k==$key}
|
27
|
+
end
|
28
|
+
}.should raise_error(ArgumentError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should accept #{key} as a proc with instance as param" do
|
32
|
+
$key = key
|
33
|
+
$default_options = @default_options
|
34
|
+
class TestComment
|
35
|
+
make_moderatable $default_options.merge({ $key => Proc.new {|obj| obj.object_id } })
|
36
|
+
end
|
37
|
+
comment = TestComment.new
|
38
|
+
comment.mm_attrs[key].should == comment.object_id
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should accept #{key} as a lambda with instance as param" do
|
42
|
+
$key = key
|
43
|
+
$default_options = @default_options
|
44
|
+
class TestComment
|
45
|
+
make_moderatable $default_options.merge({ $key => lambda {|obj| obj.object_id } })
|
46
|
+
end
|
47
|
+
comment = TestComment.new
|
48
|
+
comment.mm_attrs[key].should == comment.object_id
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should accept #{key} as a method name and be able to call it" do
|
52
|
+
$key = key
|
53
|
+
$default_options = @default_options
|
54
|
+
class TestComment
|
55
|
+
make_moderatable $default_options.merge({ $key => :test_method })
|
56
|
+
def test_method; 'wassup'; end
|
57
|
+
end
|
58
|
+
comment = TestComment.new
|
59
|
+
comment.mm_attrs[key].should == 'wassup'
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should include the profile url" do
|
65
|
+
$default_options = @default_options
|
66
|
+
lambda {
|
67
|
+
$default_options[:profile_info][:profile_url] = nil
|
68
|
+
class TestComment
|
69
|
+
make_moderatable $default_options
|
70
|
+
end
|
71
|
+
}.should raise_error(ArgumentError)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should save editable_attrs as empty array by default" do
|
75
|
+
$default_options = @default_options
|
76
|
+
class TestComment
|
77
|
+
make_moderatable $default_options.reject{|k,v| k == :editable_attrs}
|
78
|
+
end
|
79
|
+
TestComment.editable_attrs.should == []
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return editable_attrs correctly" do
|
83
|
+
$default_options = @default_options
|
84
|
+
class TestComment
|
85
|
+
make_moderatable $default_options
|
86
|
+
end
|
87
|
+
TestComment.editable_attrs.should == [:body]
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'getting the mm attributes' do
|
91
|
+
|
92
|
+
before :each do
|
93
|
+
class TestComment
|
94
|
+
make_moderatable :content_type => lambda{|obj| "#{obj.object_id} hello"},
|
95
|
+
:profile_info => {
|
96
|
+
:email => lambda{|obj| obj.test_user.email},
|
97
|
+
:profile_url => lambda{|obj| "localhost:3000/users/#{obj.test_user.id}"},
|
98
|
+
},
|
99
|
+
:item_url => lambda{|obj| "comments/#{obj.object_id}"},
|
100
|
+
:editable_attrs => [:body, :name]
|
101
|
+
def mm_content
|
102
|
+
{:body => 'wassup', :name => 'yo'}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@comment = TestComment.new(:test_user => @test_user)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should return the dynamically generated attributes' do
|
109
|
+
@comment.mm_attrs.should == {
|
110
|
+
:content_type => "#{@comment.object_id} hello",
|
111
|
+
:profile_info => {
|
112
|
+
:email => @comment.test_user.email,
|
113
|
+
:profile_url => "localhost:3000/users/#{@test_user.id}"
|
114
|
+
},
|
115
|
+
:item_url => "comments/#{@comment.object_id}"}
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should return the content' do
|
119
|
+
@comment.mm_content.should == {:body => 'wassup', :name => 'yo'}
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "destroying" do
|
125
|
+
before( :each ) do
|
126
|
+
@comment = TestComment.new(:title=>'foo', :test_user=>@test_user)
|
127
|
+
@comment.stub!(:create_mm_item).and_return(true)
|
128
|
+
@comment.stub!(:moderated?).and_return(true)
|
129
|
+
@comment.save
|
130
|
+
@mocked_resource = mock('resource')
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should fire a callback when destroyed" do
|
134
|
+
@mocked_resource.should_receive(:delete)
|
135
|
+
RestClient::Resource.should_receive(:new).and_return(@mocked_resource)
|
136
|
+
@comment.destroy
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should use the method " do
|
140
|
+
@comment.should_receive(:mm_item_url).and_return('my_url')
|
141
|
+
@mocked_resource.stub!(:delete)
|
142
|
+
RestClient::Resource.stub!(:new).with('my_url').and_return(@mocked_resource)
|
143
|
+
@comment.destroy
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe ModMonkey::Moderatables do
|
5
|
+
|
6
|
+
describe "adding all moderatable class" do
|
7
|
+
|
8
|
+
it "should return moderatables" do
|
9
|
+
ModMonkey::Moderatables.moderatables.should == [TestComment]
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class ModeratableController < ActionController::Base
|
4
|
+
|
5
|
+
extend ModMonkey::ProfileControllerActMethods
|
6
|
+
make_moderatable
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ModeratableController do
|
11
|
+
|
12
|
+
it "should have an update method" do
|
13
|
+
pending
|
14
|
+
put :update
|
15
|
+
response.should be_success
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe TestUser do
|
4
|
+
|
5
|
+
describe "making our profile moderatable" do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@user = TestUser.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have the apply_mod_monkey_params method" do
|
12
|
+
pending
|
13
|
+
@user.should be_respond_to(:apply_mod_monkey_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
MM_API_DOMAIN = "http://localhost:3002"
|
2
|
+
SITE_URL = "http://localhost:3001"
|
3
|
+
MM_API_KEY = "public"
|
4
|
+
MM_PRIOVATE_KEY = "private"
|
5
|
+
SITE_HOSTNAME = "localhost"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'spec'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rubygems'
|
11
|
+
gem 'rspec'
|
12
|
+
require 'spec'
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
16
|
+
|
17
|
+
require 'rubygems'
|
18
|
+
require 'activerecord'
|
19
|
+
require 'action_controller'
|
20
|
+
require 'mocha'
|
21
|
+
|
22
|
+
ActiveRecord::Base.establish_connection({
|
23
|
+
:adapter => 'sqlite3',
|
24
|
+
:database => ':memory:'
|
25
|
+
})
|
26
|
+
|
27
|
+
# define a migration
|
28
|
+
class TestSchema < ActiveRecord::Migration
|
29
|
+
def self.up
|
30
|
+
create_table :test_comments do |t|
|
31
|
+
t.string :title
|
32
|
+
t.integer :test_user_id
|
33
|
+
t.string :mm_key
|
34
|
+
t.string :mm_approved
|
35
|
+
t.string :mm_id
|
36
|
+
t.timestamps
|
37
|
+
end
|
38
|
+
|
39
|
+
create_table :test_users do |t|
|
40
|
+
t.text :name
|
41
|
+
t.string :email
|
42
|
+
t.boolean :banned
|
43
|
+
t.timestamps
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.down
|
48
|
+
drop_table :test_users
|
49
|
+
drop_table :test_comments
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ActiveRecord::Base.connection # this creates the DB
|
54
|
+
# run the migration
|
55
|
+
TestSchema.migrate(:up)
|
56
|
+
|
57
|
+
require 'modmonkey_client'
|
58
|
+
require 'spec/test_comment'
|
59
|
+
require 'spec/test_user'
|
60
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class TestComment < ActiveRecord::Base
|
2
|
+
belongs_to :test_user
|
3
|
+
|
4
|
+
extend ModMonkey::Item::ActMethods
|
5
|
+
make_moderatable :content_type=>'text',
|
6
|
+
:profile_info => {
|
7
|
+
:email => lambda{|obj| obj.test_user.email},
|
8
|
+
:profile_url => lambda{|obj| SITE_URL+"/test_users/#{obj.test_user.id}"}
|
9
|
+
},
|
10
|
+
:item_url => lambda{|obj| SITE_URL+"/test_comments/#{obj.id}"},
|
11
|
+
:editable_attrs => [:body]
|
12
|
+
|
13
|
+
def mm_content
|
14
|
+
{ :body => self.body }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/spec/test_user.rb
ADDED
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: newbamboo-modmonkey_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- New Bamboo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-31 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: me@mloughran.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- History.txt
|
26
|
+
- Manifest.txt
|
27
|
+
- PostInstall.txt
|
28
|
+
- README.txt
|
29
|
+
- VERSION.yml
|
30
|
+
- lib/modmonkey_client
|
31
|
+
- lib/modmonkey_client/item.rb
|
32
|
+
- lib/modmonkey_client/mod_monkey.rb
|
33
|
+
- lib/modmonkey_client/moderatables.rb
|
34
|
+
- lib/modmonkey_client/profile.rb
|
35
|
+
- lib/modmonkey_client.rb
|
36
|
+
- spec/modmonkey_client
|
37
|
+
- spec/modmonkey_client/item_controller_spec.rb
|
38
|
+
- spec/modmonkey_client/item_model_spec.rb
|
39
|
+
- spec/modmonkey_client/moderatables_spec.rb
|
40
|
+
- spec/modmonkey_client/profile_controller_spec.rb
|
41
|
+
- spec/modmonkey_client/profile_model_spec.rb
|
42
|
+
- spec/spec.opts
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
- spec/test_comment.rb
|
45
|
+
- spec/test_user.rb
|
46
|
+
has_rdoc: false
|
47
|
+
homepage: http://github.com/newbamboo/modmonkey_client
|
48
|
+
licenses:
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --inline-source
|
52
|
+
- --charset=UTF-8
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.5
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Client gem for modmonkey
|
74
|
+
test_files: []
|
75
|
+
|