appbase 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +6 -3
- data/lib/appbase/controllers/app_base_controller.rb +85 -54
- data/lib/appbase/model_concern.rb +162 -124
- data/lib/appbase/railtie.rb +157 -82
- data/lib/appbase/registry.rb +51 -23
- data/lib/appbase/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d24b5aefaba7ab3de7fa709dced97ff3d2b24539
|
4
|
+
data.tar.gz: 8a666834bc752c9128b37e94845ae4ca7272f192
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b41847490b989888115964cda8848be3d3417117391958dadebc0d6696f01daaa090f0e99fedb4c7177e0763f370cb067a73e46b90e1915ecd6b4a06a3ecb2c0
|
7
|
+
data.tar.gz: 129624fb6e14b2c6ef94a0f3033997101e79b3b7ac50081ef9f93f38be7924ecb3811d42ec62eaf6c5376725d06da3dcd5fb5286d50aa227767e85f960e6f750
|
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
[](https://travis-ci.org/bestmike007/appbase)
|
2
|
+
[](https://codeclimate.com/github/bestmike007/appbase)
|
3
|
+
[](https://codeclimate.com/github/bestmike007/appbase)
|
4
|
+
[](http://badge.fury.io/rb/appbase)
|
2
5
|
|
3
6
|
Nowadays BaaS and mBaaS platforms (e.g. [firebase](https://www.firebase.com/), [parse](https://www.parse.com/), [appbase.io](https://appbase.io/)) abound. Open source solutions (e.g. [usergrid](http://usergrid.incubator.apache.org/) using LAMP, [helios](http://helios.io/) using Ruby, [deployd](http://deployd.com/) and [StrongLoop](http://strongloop.com/) using nodejs, and a lot more) are also available. And appbase is much less than those.
|
4
7
|
|
@@ -154,7 +157,7 @@ Basic CRUD api conforms to the representational state transfer (REST) architectu
|
|
154
157
|
Request to create a model with JSON serialized body:
|
155
158
|
|
156
159
|
```
|
157
|
-
|
160
|
+
POST /_api/note HTTP/1.1
|
158
161
|
HOST xxx
|
159
162
|
Content-Type: application/json
|
160
163
|
|
@@ -179,7 +182,7 @@ HTTP/1.1 200 OK
|
|
179
182
|
|
180
183
|
#### Update
|
181
184
|
|
182
|
-
Almost the same as create except for adding the `:id` parameter (e.g. `/_api/note/:id`):
|
185
|
+
Almost the same as create except for using `PUT` and adding the `:id` parameter (e.g. `/_api/note/:id`):
|
183
186
|
|
184
187
|
```
|
185
188
|
PUT /_api/note/1 HTTP/1.1
|
@@ -254,4 +257,4 @@ You're welcome to contribute to this project by creating an issue / a pull reque
|
|
254
257
|
|
255
258
|
## License
|
256
259
|
|
257
|
-
Appbase is released under the [MIT License](http://opensource.org/licenses/MIT).
|
260
|
+
Appbase is released under the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -27,43 +27,42 @@ class AppBaseController < ActionController::Base
|
|
27
27
|
-
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def permits(model, arg_str=false)
|
31
|
+
if arg_str
|
32
|
+
"[#{model.columns.map { |item| ":" + item.name }.join(", ")}]"
|
33
|
+
else
|
34
|
+
model.columns.map { |item| item.name.to_sym }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_create_or_update_stub(op, model, prepare)
|
31
39
|
m = model.name
|
32
|
-
permits = model.columns.map { |item| item.name }.to_json
|
33
40
|
self.class_eval %-
|
34
|
-
def
|
35
|
-
|
36
|
-
if !#{m}.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
41
|
+
def #{op}_#{AppBase.underscore m}
|
42
|
+
#{prepare}
|
43
|
+
raise "unauthorized" if !#{m}.allow_#{op}?(current_user, obj)
|
44
|
+
obj.save!
|
45
|
+
rs = { status: 'ok' }
|
46
|
+
#{ 'rs[:id] = obj.id' if op == :create }
|
47
|
+
render json: rs
|
42
48
|
rescue Exception => e
|
43
49
|
render json: { status: 'error', msg: e.to_s }
|
44
50
|
end
|
45
51
|
-
|
46
52
|
end
|
53
|
+
private :add_create_or_update_stub
|
54
|
+
|
55
|
+
def add_create_stub(model)
|
56
|
+
add_create_or_update_stub :create, model, %-
|
57
|
+
obj = #{model.name}.new(params.except(:action, :controller, :id).permit(#{permits(model, true)}))
|
58
|
+
-
|
59
|
+
end
|
47
60
|
|
48
61
|
def add_update_stub(model)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
obj = #{m}.find(params[:id])
|
54
|
-
if obj.nil?
|
55
|
-
return render json: { status: 'error', msg: 'not_found' }
|
56
|
-
end
|
57
|
-
obj.update_attributes(params.except(:action, :controller, :id).permit(#{permits}))
|
58
|
-
if !#{m}.allow_update?(current_user, obj)
|
59
|
-
render json: { status: "error", msg: "unauthorized" }
|
60
|
-
else
|
61
|
-
obj.save!
|
62
|
-
render json: { status: 'ok' }
|
63
|
-
end
|
64
|
-
rescue Exception => e
|
65
|
-
render json: { status: 'error', msg: e.to_s }
|
66
|
-
end
|
62
|
+
add_create_or_update_stub :update, model, %-
|
63
|
+
obj = #{model.name}.find(params[:id])
|
64
|
+
raise 'not_found' if obj.nil?
|
65
|
+
obj.update_attributes(params.except(:action, :controller, :id).permit(#{permits(model, true)}))
|
67
66
|
-
|
68
67
|
end
|
69
68
|
|
@@ -89,7 +88,6 @@ class AppBaseController < ActionController::Base
|
|
89
88
|
|
90
89
|
def add_query_stub(model)
|
91
90
|
m = model.name
|
92
|
-
columns = model.columns.map{|c|c.name}
|
93
91
|
self.class_eval %-
|
94
92
|
def query_#{AppBase.underscore m}
|
95
93
|
query = #{m}.accessible_by(current_user)
|
@@ -141,36 +139,69 @@ class AppBaseController < ActionController::Base
|
|
141
139
|
end
|
142
140
|
|
143
141
|
def add_rpc_method_stub(bound_method, auth=false)
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
142
|
+
RpcMethodStubHelper.new(bound_method, auth).add_stub(self)
|
143
|
+
end
|
144
|
+
|
145
|
+
class RpcMethodStubHelper
|
146
|
+
|
147
|
+
def initialize(bound_method, auth=false)
|
148
|
+
@bound_method = bound_method
|
149
|
+
@auth = auth
|
150
|
+
@method_name = bound_method.name
|
151
|
+
@model_name = bound_method.receiver.name.to_s.extend(AppBase::StringExtension)
|
152
|
+
init
|
149
153
|
end
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
154
|
+
|
155
|
+
def add_stub(controller)
|
156
|
+
controller.class_eval %-
|
157
|
+
def rpc_#{@model_name.underscore}_#{@method_name}
|
158
|
+
#{@requires.map{|p|"params.require #{p}"}.join(';')}
|
159
|
+
render json: { status: 'ok', data: #{@model_name}.#{@method_name}(#{@parameters.join(', ')}) }
|
160
|
+
rescue Exception => e
|
161
|
+
render json: { status: 'error', msg: e.to_s }
|
162
|
+
end
|
163
|
+
-
|
156
164
|
end
|
157
|
-
|
158
|
-
|
165
|
+
|
166
|
+
private
|
167
|
+
def init
|
168
|
+
init_parameters do |parameters, need_params|
|
169
|
+
@requires = parameters.map{|p|":#{p[1]}"}
|
170
|
+
@parameters = @auth ? ['current_user'] : []
|
171
|
+
@requires.each { |p| @parameters << "params[#{p}]" }
|
172
|
+
if need_params
|
173
|
+
@parameters.push "params.except(:action, :controller#{@requires.count > 0 ? ", #{@requires.join(', ')}" : ""})"
|
174
|
+
end
|
175
|
+
end
|
159
176
|
end
|
160
|
-
|
161
|
-
parameters
|
162
|
-
|
163
|
-
|
164
|
-
|
177
|
+
|
178
|
+
def pre_init_parameters(parameters)
|
179
|
+
if @auth && (parameters.count == 0 || parameters[0][0] != :req)
|
180
|
+
raise "#{@model_name}.#{@method_name} does not accept current user identity as the first parameter. Using `expose_to_appbase :method_name, auth: false` to expose #{@model_name}.#{@method_name} to appbase without user authentication."
|
181
|
+
end
|
165
182
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
rescue Exception => e
|
171
|
-
render json: { status: 'error', msg: e.to_s }
|
183
|
+
|
184
|
+
def post_init_parameters(parameters)
|
185
|
+
if parameters.find{|p|p[0]!=:req}
|
186
|
+
raise "Error exposing #{@model_name}.#{@method_name} to appbase engine, appbase does not support rest/optional parameters, use options instead!"
|
172
187
|
end
|
173
|
-
|
188
|
+
end
|
189
|
+
|
190
|
+
def init_parameters
|
191
|
+
parameters = @bound_method.parameters
|
192
|
+
pre_init_parameters(parameters)
|
193
|
+
|
194
|
+
need_params = false
|
195
|
+
if parameters.count > 0 && parameters.last[0] == :opt
|
196
|
+
need_params = true
|
197
|
+
parameters = parameters[(@auth ? 1 : 0)..-2]
|
198
|
+
else
|
199
|
+
parameters = parameters[(@auth ? 1 : 0)..-1]
|
200
|
+
end
|
201
|
+
|
202
|
+
post_init_parameters(parameters)
|
203
|
+
yield parameters, need_params
|
204
|
+
end
|
174
205
|
end
|
175
206
|
|
176
207
|
end
|
@@ -3,6 +3,129 @@ require 'active_support'
|
|
3
3
|
module AppBase
|
4
4
|
|
5
5
|
module ModelConcern
|
6
|
+
|
7
|
+
class InvalidUsage < Exception
|
8
|
+
end
|
9
|
+
|
10
|
+
class ModelConcernHelper
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def validate_crud(crud)
|
15
|
+
if [:create, :update, :delete, :query].index(crud).nil?
|
16
|
+
raise "Unsupported crud operation: #{crud}, available options: create, update, delete, query"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def model_inject(method_name=nil, &block)
|
21
|
+
AppBase::Engine.after_initialized do
|
22
|
+
user_identity_attr = "#{AppBase::Engine::UserIdentity.underscore}_id"
|
23
|
+
if method_name.nil?
|
24
|
+
method_body = block.call(user_identity_attr)
|
25
|
+
@model.class_eval method_body
|
26
|
+
else
|
27
|
+
@model.define_singleton_method method_name.to_sym, &block
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def show_usage(crud)
|
33
|
+
raise %-
|
34
|
+
allow_#{crud} usage:
|
35
|
+
allow_#{crud} :mine
|
36
|
+
allow_#{crud} :#{ crud == :query ? 'within' : 'if' } => :a_singleton_method
|
37
|
+
allow_#{crud} :#{ crud == :query ? 'within' : 'if' } do |current_user_identity#{ crud == :query ? '' : ', model_instance' }|
|
38
|
+
# #{ crud == :query ? 'return fitlered query, e.g. Note.where(:user_id => current_user_identity.id)' : 'return true if allowed' }
|
39
|
+
end
|
40
|
+
-
|
41
|
+
end
|
42
|
+
|
43
|
+
def allow_mine(crud)
|
44
|
+
model_inject do |user_identity_attr|
|
45
|
+
crud == :query ? %-
|
46
|
+
def self.accessible_by(user)
|
47
|
+
#{@model.name}.where(:#{user_identity_attr} => user.id)
|
48
|
+
end
|
49
|
+
- : %-
|
50
|
+
def self.allow_#{crud}?(user, obj)
|
51
|
+
user.id == obj.#{user_identity_attr}
|
52
|
+
end
|
53
|
+
-
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def allow_criteria_with_block(crud, block)
|
58
|
+
show_usage(crud) if crud == :query && block.parameters.count != 1
|
59
|
+
show_usage(crud) if crud != :query && block.parameters.count != 2
|
60
|
+
model_inject crud == :query ? :accessible_by : "allow_#{crud}", &block
|
61
|
+
end
|
62
|
+
|
63
|
+
def allow_criteria_with_method_alias(crud, method_name)
|
64
|
+
show_usage(crud) if method_name.nil? || !method_name.instance_of?(Symbol)
|
65
|
+
model_inject do |user_identity_attr|
|
66
|
+
crud == :query ? %-
|
67
|
+
def self.accessible_by(user)
|
68
|
+
#{@model.name}.#{method_name} user
|
69
|
+
end
|
70
|
+
- : %-
|
71
|
+
def self.allow_#{crud}?(user, obj)
|
72
|
+
#{@model.name}.#{method_name} user, obj
|
73
|
+
end
|
74
|
+
-
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
public
|
79
|
+
|
80
|
+
def crud_allow(crud, criteria=:mine, &block)
|
81
|
+
validate_crud crud
|
82
|
+
|
83
|
+
if criteria == :mine
|
84
|
+
allow_mine crud
|
85
|
+
else
|
86
|
+
key = crud == :query ? :within : :if
|
87
|
+
if criteria.instance_of? Hash
|
88
|
+
allow_criteria_with_method_alias(crud, criteria[key])
|
89
|
+
else
|
90
|
+
show_usage(crud) if criteria != key || !block_given?
|
91
|
+
allow_criteria_with_block(crud, block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
AppBase::Registry.register_crud @model, crud
|
95
|
+
end
|
96
|
+
|
97
|
+
def symbol_array_manipulate(op, source, options)
|
98
|
+
raise InvalidUsage if op != :only && op != :except
|
99
|
+
if options.has_key? op
|
100
|
+
operands = options[op]
|
101
|
+
operands = [operands] if operands.instance_of?(String) || operands.instance_of?(Symbol)
|
102
|
+
raise InvalidUsage unless operands.instance_of?(Array)
|
103
|
+
operands = operands.map {|c|c.to_sym}
|
104
|
+
source.send({ only: '&', except: "-" }[op], operands)
|
105
|
+
else
|
106
|
+
source
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
def initialize(model)
|
112
|
+
@model = model
|
113
|
+
end
|
114
|
+
|
115
|
+
class << self
|
116
|
+
|
117
|
+
def [](model)
|
118
|
+
raise "Invalid model" if model.class != Class
|
119
|
+
helpers[model] ||= ModelConcernHelper.new(model)
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
def helpers
|
124
|
+
@helpers ||= {}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
6
129
|
|
7
130
|
extend ActiveSupport::Concern
|
8
131
|
|
@@ -19,120 +142,42 @@ module AppBase
|
|
19
142
|
end
|
20
143
|
end
|
21
144
|
|
22
|
-
def appbase_allow(crud, criteria=:mine, &block)
|
23
|
-
if [:create, :update, :delete, :query].index(crud).nil?
|
24
|
-
raise "Unsupported crud operation: #{crud}, available options: create, update, delete, query"
|
25
|
-
end
|
26
|
-
model = self
|
27
|
-
if criteria == :mine
|
28
|
-
# allow_xxx :mine or simply allow_xxx
|
29
|
-
AppBase::Engine.after_initialized do
|
30
|
-
user_identity_attr = "#{AppBase::Engine::UserIdentity.underscore}_id"
|
31
|
-
model.class_eval crud == :query ? %-
|
32
|
-
def self.accessible_by(user)
|
33
|
-
#{model.name}.where(:#{user_identity_attr} => user.id)
|
34
|
-
end
|
35
|
-
- : %-
|
36
|
-
def self.allow_#{crud}?(user, obj)
|
37
|
-
user.id == obj.#{user_identity_attr}
|
38
|
-
end
|
39
|
-
-
|
40
|
-
end
|
41
|
-
elsif crud != :query && criteria == :if && block_given? && block.parameters.count == 2
|
42
|
-
# allow_xxx :if do; end
|
43
|
-
AppBase::Engine.after_initialized do
|
44
|
-
user_identity_attr = "#{AppBase::Engine::UserIdentity.underscore}_id"
|
45
|
-
model.define_singleton_method "allow_#{crud}".to_sym, &block
|
46
|
-
end
|
47
|
-
elsif crud == :query && criteria == :within && block_given? && block.parameters.count == 1
|
48
|
-
# allow_query :within {|current_user| Model.where(...)}
|
49
|
-
AppBase::Engine.after_initialized do
|
50
|
-
user_identity_attr = "#{AppBase::Engine::UserIdentity.underscore}_id"
|
51
|
-
model.define_singleton_method :accessible_by, &block
|
52
|
-
end
|
53
|
-
elsif crud != :query && riteria.instance_of?(Hash) && criteria.has_key?(:if) && criteria[:if].instance_of?(Symbol)
|
54
|
-
# :if => :a_singleton_method
|
55
|
-
AppBase::Engine.after_initialized do
|
56
|
-
user_identity_attr = "#{AppBase::Engine::UserIdentity.underscore}_id"
|
57
|
-
model.class_eval %-
|
58
|
-
def self.allow_#{crud}?(user, obj)
|
59
|
-
#{model.name}.#{criteria[:if]} user
|
60
|
-
end
|
61
|
-
-
|
62
|
-
end
|
63
|
-
elsif crud == :query && criteria.instance_of?(Hash) && criteria.has_key?(:within) && criteria[:within].instance_of?(Symbol)
|
64
|
-
# allow_query :within => :a_singleton_query_method
|
65
|
-
AppBase::Engine.after_initialized do
|
66
|
-
user_identity_attr = "#{AppBase::Engine::UserIdentity.underscore}_id"
|
67
|
-
model.class_eval %-
|
68
|
-
def self.accessible_by(user)
|
69
|
-
#{model.name}.#{criteria[:within]} user
|
70
|
-
end
|
71
|
-
-
|
72
|
-
end
|
73
|
-
else
|
74
|
-
raise %-
|
75
|
-
allow_#{crud} usage:
|
76
|
-
allow_#{crud} :mine
|
77
|
-
allow_#{crud} :#{ crud == :query ? 'within' : 'if' } => :a_singleton_method
|
78
|
-
allow_#{crud} :#{ crud == :query ? 'within' : 'if' } do |current_user_identity#{ crud == :query ? '' : ', model_instance' }|
|
79
|
-
# #{ crud == :query ? 'return fitlered query, e.g. Note.where(:user_id => current_user_identity.id)' : 'return true if allowed' }
|
80
|
-
end
|
81
|
-
-
|
82
|
-
end
|
83
|
-
AppBase::Registry.register_crud self, crud
|
84
|
-
end
|
85
|
-
|
86
145
|
def allow_create(criteria=:mine, &block)
|
87
|
-
|
146
|
+
appbase_helper.crud_allow(:create, criteria, &block)
|
88
147
|
end
|
89
148
|
|
90
149
|
def allow_update(criteria=:mine, &block)
|
91
|
-
|
150
|
+
appbase_helper.crud_allow(:update, criteria, &block)
|
92
151
|
end
|
93
152
|
|
94
153
|
def allow_delete(criteria=:mine, &block)
|
95
|
-
|
154
|
+
appbase_helper.crud_allow(:delete, criteria, &block)
|
96
155
|
end
|
97
156
|
|
98
157
|
def allow_query(criteria=:mine, &block)
|
99
|
-
|
158
|
+
appbase_helper.crud_allow(:query, criteria, &block)
|
100
159
|
end
|
101
160
|
|
102
161
|
def restrict_query_columns(options={})
|
103
|
-
|
104
|
-
raise %-
|
105
|
-
restrict_query_columns usage:
|
106
|
-
restrict_query_columns <only | except>: <single_column | column_list>
|
107
|
-
examples:
|
108
|
-
restrict_query_columns only: [:user_id, :created_at, :updated_at]
|
109
|
-
restrict_query_columns only: :updated_at
|
110
|
-
restrict_query_columns except: [:content]
|
111
|
-
-
|
112
|
-
}
|
113
|
-
show_usage.call if !options || !options.instance_of?(Hash)
|
162
|
+
raise InvalidUsage if !options || !options.instance_of?(Hash)
|
114
163
|
columns = self.columns.map{|c|c.name.to_sym}
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
on_columns = [on_columns] if on_columns.instance_of?(String) || on_columns.instance_of?(Symbol)
|
119
|
-
show_usage.call unless on_columns.instance_of?(Array)
|
120
|
-
on_columns = on_columns.map {|c|c.to_sym}
|
121
|
-
columns &= on_columns
|
122
|
-
end
|
123
|
-
# except columns
|
124
|
-
if options.has_key? :except
|
125
|
-
except_columns = options[:except]
|
126
|
-
except_columns = [except_columns] if except_columns.instance_of?(String) || except_columns.instance_of?(Symbol)
|
127
|
-
show_usage.call unless except_columns.instance_of?(Array)
|
128
|
-
except_columns = except_columns.map {|c|c.to_sym}
|
129
|
-
columns -= except_columns
|
130
|
-
end
|
164
|
+
|
165
|
+
columns = appbase_helper.symbol_array_manipulate :only, columns, options
|
166
|
+
columns = appbase_helper.symbol_array_manipulate :except, columns, options
|
131
167
|
|
132
168
|
self.define_singleton_method :appbase_queryable_columns do
|
133
169
|
columns
|
134
170
|
end
|
135
171
|
|
172
|
+
rescue InvalidUsage
|
173
|
+
raise %-
|
174
|
+
restrict_query_columns usage:
|
175
|
+
restrict_query_columns <only | except>: <single_column | column_list>
|
176
|
+
examples:
|
177
|
+
restrict_query_columns only: [:user_id, :created_at, :updated_at]
|
178
|
+
restrict_query_columns only: :updated_at
|
179
|
+
restrict_query_columns except: [:content]
|
180
|
+
-
|
136
181
|
end
|
137
182
|
|
138
183
|
def appbase_queryable_operators
|
@@ -140,38 +185,13 @@ module AppBase
|
|
140
185
|
end
|
141
186
|
|
142
187
|
def restrict_query_operators(*columns)
|
143
|
-
|
144
|
-
raise %-
|
145
|
-
restrict_query_operators usage:
|
146
|
-
restrict_query_operators :column1, :column2, <only | except>: <:equal | :compare | :in>
|
147
|
-
examples:
|
148
|
-
restrict_query_operators :user_id, :created_at, :updated_at, only: [:equal, :compare]
|
149
|
-
restrict_query_operators :user_id, :created_at, :updated_at, except: :in
|
150
|
-
restrict_query_operators :title, only: :equal
|
151
|
-
-
|
152
|
-
}
|
153
|
-
show_usage.call if columns.count < 2 || !columns.last.instance_of?(Hash)
|
188
|
+
check_before_restrict_query_operators columns
|
154
189
|
*columns, options = columns
|
155
|
-
show_usage.call unless options.has_key?(:only) || options.has_key?(:except)
|
156
190
|
operators = appbase_queryable_operators
|
157
191
|
|
158
192
|
set = [:equal, :compare, :in]
|
159
|
-
|
160
|
-
|
161
|
-
allows = options[:only]
|
162
|
-
allows = [allows] if allows.instance_of?(String) || allows.instance_of?(Symbol)
|
163
|
-
show_usage.call unless allows.instance_of?(Array)
|
164
|
-
allows = allows.map {|c|c.to_sym}
|
165
|
-
set &= allows
|
166
|
-
end
|
167
|
-
# except columns
|
168
|
-
if options.has_key? :except
|
169
|
-
excepts = options[:except]
|
170
|
-
excepts = [excepts] if excepts.instance_of?(String) || excepts.instance_of?(Symbol)
|
171
|
-
show_usage.call unless excepts.instance_of?(Array)
|
172
|
-
excepts = excepts.map {|c|c.to_sym}
|
173
|
-
set -= excepts
|
174
|
-
end
|
193
|
+
set = appbase_helper.symbol_array_manipulate :only, set, options
|
194
|
+
set = appbase_helper.symbol_array_manipulate :except, set, options
|
175
195
|
|
176
196
|
columns.each do |c|
|
177
197
|
operators[c.to_sym] = set
|
@@ -180,10 +200,28 @@ module AppBase
|
|
180
200
|
self.define_singleton_method :appbase_queryable_operators do
|
181
201
|
operators
|
182
202
|
end
|
183
|
-
|
203
|
+
rescue InvalidUsage
|
204
|
+
raise %-
|
205
|
+
restrict_query_operators usage:
|
206
|
+
restrict_query_operators :column1, :column2, <only | except>: <:equal | :compare | :in>
|
207
|
+
examples:
|
208
|
+
restrict_query_operators :user_id, :created_at, :updated_at, only: [:equal, :compare]
|
209
|
+
restrict_query_operators :user_id, :created_at, :updated_at, except: :in
|
210
|
+
restrict_query_operators :title, only: :equal
|
211
|
+
-
|
184
212
|
end
|
185
213
|
|
214
|
+
private
|
215
|
+
|
216
|
+
def check_before_restrict_query_operators(columns)
|
217
|
+
raise InvalidUsage if columns.count < 2 || !columns.last.instance_of?(Hash)
|
218
|
+
options = columns.last
|
219
|
+
raise InvalidUsage unless options.has_key?(:only) || options.has_key?(:except)
|
220
|
+
end
|
186
221
|
|
222
|
+
def appbase_helper
|
223
|
+
ModelConcernHelper[self]
|
224
|
+
end
|
187
225
|
end
|
188
226
|
|
189
227
|
end
|
data/lib/appbase/railtie.rb
CHANGED
@@ -11,90 +11,156 @@ module AppBase
|
|
11
11
|
|
12
12
|
class << self
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
class RpcMethodInitializer
|
15
|
+
|
16
|
+
def initialize(config)
|
17
|
+
@model = config[:model]
|
18
|
+
@method = config[:method]
|
19
|
+
@auth = config[:auth]
|
20
|
+
end
|
21
|
+
|
22
|
+
def init
|
23
|
+
pre_init
|
24
|
+
add_controller_stub
|
25
|
+
add_route
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def pre_init
|
30
|
+
model_name = @model.name
|
31
|
+
if !@model.respond_to?(@method)
|
32
|
+
raise "#{model_name} does not respond to #{@method}."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_controller_stub
|
37
|
+
bound_method = @model.method @method
|
38
|
+
AppBaseController.add_rpc_method_stub(bound_method, @auth)
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_route
|
42
|
+
model_name_underscore = AppBase.underscore @model.name
|
43
|
+
method_name = @method
|
44
|
+
AppBase::Engine.routes.append do
|
45
|
+
post "/#{model_name_underscore}/#{method_name}" => "app_base#rpc_#{model_name_underscore}_#{method_name}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class CrudInitializer
|
51
|
+
|
52
|
+
def initialize(model, op)
|
53
|
+
@model = model
|
54
|
+
@op = op
|
55
|
+
@http_methods = { create: :post, update: :put, delete: :delete, query: :get }
|
56
|
+
end
|
57
|
+
|
58
|
+
def init
|
59
|
+
pre_init
|
60
|
+
add_controller_stub
|
61
|
+
add_route
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def pre_init
|
66
|
+
raise "Unexpected crud operation: #{@op}" if !@http_methods.has_key?(@op)
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_controller_stub
|
70
|
+
AppBaseController.send "add_#{@op}_stub".to_sym, @model
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_route
|
74
|
+
model_name_underscore = AppBase.underscore @model.name
|
75
|
+
url_path = "/#{model_name_underscore}"
|
76
|
+
url_path += "/:id" if @op == :update || @op == :delete
|
77
|
+
http_method = @http_methods[@op]
|
78
|
+
op = @op
|
79
|
+
AppBase::Engine.routes.append do
|
80
|
+
match url_path, to: "app_base##{op}_#{model_name_underscore}", via: http_method
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
17
85
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
AppBase::Engine.routes.append do
|
40
|
-
put "/#{model_name_underscore}" => "app_base#create_#{model_name_underscore}"
|
41
|
-
end
|
42
|
-
when :update
|
43
|
-
AppBaseController.add_update_stub(model)
|
44
|
-
AppBase::Engine.routes.append do
|
45
|
-
put "/#{model_name_underscore}/:id" => "app_base#update_#{model_name_underscore}"
|
46
|
-
end
|
47
|
-
when :delete
|
48
|
-
AppBaseController.add_delete_stub(model)
|
49
|
-
AppBase::Engine.routes.append do
|
50
|
-
delete "/#{model_name_underscore}/:id" => "app_base#delete_#{model_name_underscore}"
|
51
|
-
end
|
52
|
-
when :query
|
53
|
-
AppBaseController.add_query_stub(model)
|
54
|
-
AppBase::Engine.routes.append do
|
55
|
-
get "/#{model_name_underscore}" => "app_base#query_#{model_name_underscore}"
|
56
|
-
end
|
86
|
+
class AppBaseEngineInitializer
|
87
|
+
|
88
|
+
def initialize
|
89
|
+
@initialized = false
|
90
|
+
@hooks = []
|
91
|
+
end
|
92
|
+
|
93
|
+
def bootstrap(app_config)
|
94
|
+
return if @initialized
|
95
|
+
@config = app_config.appbase
|
96
|
+
initialize_user_identity
|
97
|
+
initialize_crud_stubs
|
98
|
+
initialize_rpc_stubs
|
99
|
+
finilize_routes
|
100
|
+
post_initialize
|
101
|
+
@initialized = true
|
102
|
+
end
|
103
|
+
|
104
|
+
def after_initialized(&block)
|
105
|
+
if @initialized
|
106
|
+
block.call
|
57
107
|
else
|
58
|
-
|
108
|
+
@hooks << block
|
59
109
|
end
|
60
110
|
end
|
61
111
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
112
|
+
private
|
113
|
+
|
114
|
+
def pre_init_user_identity
|
115
|
+
if @config.user_identity.nil?
|
116
|
+
raise "AppBase configuration error: please use `config.appbase.user_identity = :UserIdentity` to specify the user identity model; and implement UserIdentity.authenticate_by_token(user, token):UserIdentity method."
|
66
117
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
post "/#{AppBase.underscore r[:model].name}/#{r[:method]}" => "app_base#rpc_#{AppBase.underscore r[:model].name}_#{r[:method]}"
|
118
|
+
user_identity = Object.const_get @config.user_identity.to_sym
|
119
|
+
if !user_identity.respond_to?(:authenticate_by_token) || user_identity.method(:authenticate_by_token).parameters.count != 2
|
120
|
+
raise "It's required to implement UserIdentity.authenticate_by_token(user, token):UserIdentity method."
|
71
121
|
end
|
72
122
|
end
|
73
123
|
|
74
|
-
|
75
|
-
|
76
|
-
|
124
|
+
def initialize_user_identity
|
125
|
+
pre_init_user_identity
|
126
|
+
AppBase::Engine.const_set :UserIdentity, @config.user_identity.to_s.extend(AppBase::StringExtension)
|
127
|
+
AppBaseController.define_useridentity @config.user_identity, @config.token_store, @config.token_key_user, @config.token_key_session
|
77
128
|
end
|
78
129
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
130
|
+
def initialize_crud_stubs
|
131
|
+
AppBase::Registry.each_crud @config.models do |model, op|
|
132
|
+
CrudInitializer.new(model, op).init
|
133
|
+
end
|
83
134
|
end
|
84
|
-
initialized = true
|
85
135
|
|
136
|
+
def initialize_rpc_stubs
|
137
|
+
AppBase::Registry.each_rpc do |r|
|
138
|
+
RpcMethodInitializer.new(r).init
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def finilize_routes
|
143
|
+
AppBase::Engine.routes.draw do
|
144
|
+
get "/appbase_version" => "app_base#version"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def post_initialize
|
149
|
+
blocks, @hooks = @hooks, []
|
150
|
+
blocks.each do |block|
|
151
|
+
block.call
|
152
|
+
end
|
153
|
+
end
|
86
154
|
end
|
87
155
|
|
88
|
-
|
89
|
-
if
|
90
|
-
|
91
|
-
else
|
92
|
-
hooks << block
|
93
|
-
end
|
156
|
+
def bootstrap(config)
|
157
|
+
@initializer = AppBaseEngineInitializer.new if !@initializer
|
158
|
+
@initializer.bootstrap(config)
|
94
159
|
end
|
95
160
|
|
96
|
-
|
97
|
-
|
161
|
+
def after_initialized(&block)
|
162
|
+
@initializer = AppBaseEngineInitializer.new if !@initializer
|
163
|
+
@initializer.after_initialized(&block)
|
98
164
|
end
|
99
165
|
|
100
166
|
end
|
@@ -102,26 +168,35 @@ module AppBase
|
|
102
168
|
end
|
103
169
|
|
104
170
|
class Railtie < Rails::Railtie
|
105
|
-
|
106
|
-
# default values for appbase configuration
|
107
|
-
config.appbase = ActiveSupport::OrderedOptions.new
|
108
|
-
config.appbase.enabled = false
|
109
|
-
config.appbase.mount = "/appbase"
|
110
|
-
config.appbase.user_identity = nil
|
111
|
-
config.appbase.token_store = :cookies # :cookies, :headers, :params
|
112
|
-
config.appbase.token_key_user = :u
|
113
|
-
config.appbase.token_key_session = :s
|
114
|
-
config.appbase.models = []
|
115
171
|
|
116
|
-
|
117
|
-
|
172
|
+
class << self
|
173
|
+
private
|
174
|
+
def setup_default(config)
|
175
|
+
return if config.respond_to? :appbase
|
176
|
+
# default values for appbase configuration
|
177
|
+
config.appbase = ActiveSupport::OrderedOptions.new
|
178
|
+
config.appbase.enabled = false
|
179
|
+
config.appbase.mount = "/appbase"
|
180
|
+
config.appbase.user_identity = nil
|
181
|
+
config.appbase.token_store = :cookies # :cookies, :headers, :params
|
182
|
+
config.appbase.token_key_user = :u
|
183
|
+
config.appbase.token_key_session = :s
|
184
|
+
config.appbase.models = []
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def enabled
|
118
189
|
if File.basename(ENV['_']) == 'rake'
|
119
190
|
puts "Running with `rake #{$*.join(' ')}`"
|
120
191
|
end
|
121
|
-
|
122
|
-
|
192
|
+
config.appbase.enabled && (File.basename(ENV['_']) != 'rake' || $*[0] == 'routes')
|
193
|
+
end
|
194
|
+
|
195
|
+
setup_default config
|
196
|
+
|
197
|
+
initializer "appbase.configure_route", :after => :add_routing_paths do |app|
|
198
|
+
if enabled
|
123
199
|
AppBase::Engine.bootstrap app.config
|
124
|
-
|
125
200
|
app.routes.append do
|
126
201
|
mount AppBase::Engine => Rails.application.config.appbase.mount
|
127
202
|
end
|
data/lib/appbase/registry.rb
CHANGED
@@ -23,36 +23,64 @@ module AppBase
|
|
23
23
|
# used once upon rails startup, cannot be reloaded by spring.
|
24
24
|
class << Registry
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
rpc_methods
|
35
|
-
|
36
|
-
|
26
|
+
class RegistryTable
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@rpc_methods = []
|
30
|
+
@crud_permissions = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def contains_rpc_registry(item)
|
34
|
+
!@rpc_methods.find{ |r| r[:model] == item[:model] && r[:method] == item[:method] }.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def register_rpc(model, method_name, options={})
|
38
|
+
rpc_registry_item = {
|
39
|
+
model: (model.instance_of?(String) || model.instance_of?(Symbol)) ? Object.const_get(model.to_sym) : model,
|
40
|
+
method: method_name.to_sym,
|
41
|
+
auth: options.has_key?(:auth) ? options[:auth] : true
|
42
|
+
}
|
43
|
+
raise "#{model}.#{method_name} has already been registered" if contains_rpc_registry(rpc_registry_item)
|
44
|
+
@rpc_methods << rpc_registry_item
|
45
|
+
end
|
46
|
+
|
47
|
+
def register_crud(model, crud)
|
48
|
+
if @crud_permissions.find{ |r| r[:model] == model && r[:crud] == crud }.nil?
|
49
|
+
@crud_permissions << { model: model, crud: crud }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def each_rpc(&block)
|
54
|
+
@rpc_methods.each(&block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def each_crud(*models, &block)
|
58
|
+
models = models.flatten.map { |model| (model.instance_of?(Symbol) || model.instance_of?(String)) ? Object.const_get(model) : model }
|
59
|
+
@crud_permissions.each do |r|
|
60
|
+
block.call r[:model], r[:crud] if models.index(r[:model])
|
61
|
+
end
|
37
62
|
end
|
38
63
|
end
|
39
64
|
|
40
|
-
|
41
|
-
|
65
|
+
def register_rpc(model, method_name, options={})
|
66
|
+
instance.register_rpc(model, method_name, options)
|
42
67
|
end
|
43
68
|
|
44
|
-
|
45
|
-
|
46
|
-
crud_permissions << { model: model, crud: crud }
|
47
|
-
end
|
69
|
+
def register_crud(model, crud)
|
70
|
+
instance.register_crud(model, crud)
|
48
71
|
end
|
49
72
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
73
|
+
def each_rpc(&block)
|
74
|
+
instance.each_rpc(&block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def each_crud(*models, &block)
|
78
|
+
instance.each_crud(*models, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def instance
|
83
|
+
@instance ||= RegistryTable.new
|
56
84
|
end
|
57
85
|
|
58
86
|
end
|
data/lib/appbase/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- bestmike007
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|