lanes 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dir-locals.el +8 -0
- data/client/lanes/Config.coffee +1 -1
- data/client/lanes/access/Extension.coffee +1 -6
- data/client/lanes/access/screens/user-management/GridUserEditor.coffee +6 -5
- data/client/lanes/access/screens/user-management/grid-popover-editor.html +2 -2
- data/client/lanes/components/grid/vendor/jquery.dataTables.js +1 -1
- data/client/lanes/components/multi-select/MultiSelect.coffee +10 -5
- data/client/lanes/components/select-field/SelectField.coffee +2 -1
- data/client/lanes/models/Base.coffee +1 -1
- data/client/lanes/models/PubSub.coffee +4 -3
- data/client/lanes/models/Sync.coffee +3 -3
- data/client/lanes/screens/ChangeListener.coffee +0 -3
- data/client/lanes/testing/ModelSaver.coffee +12 -1
- data/client/lanes/views/Base.coffee +1 -1
- data/client/lanes/views/Helpers.coffee +2 -1
- data/client/lanes/views/SaveNotify.coffee +9 -7
- data/client/lanes/views/TimedMask.coffee +1 -1
- data/lanes.gemspec +1 -1
- data/lib/lanes/access/authentication_provider.rb +17 -11
- data/lib/lanes/access/config/routes.rb +1 -1
- data/lib/lanes/access/extension.rb +9 -2
- data/lib/lanes/access/role.rb +12 -0
- data/lib/lanes/access.rb +8 -8
- data/lib/lanes/api/null_authentication_provider.rb +2 -2
- data/lib/lanes/api/request_wrapper.rb +10 -10
- data/lib/lanes/concerns/association_extensions.rb +16 -7
- data/lib/lanes/concerns/pub_sub.rb +55 -30
- data/lib/lanes/guard_tasks.rb +7 -3
- data/lib/lanes/version.rb +1 -1
- data/{appy-app → spec/command-reference-files/initial}/.gitignore +0 -0
- data/{appy-app → spec/command-reference-files/initial}/Gemfile +1 -1
- data/{appy-app → spec/command-reference-files/initial}/Guardfile +0 -0
- data/{appy-app → spec/command-reference-files/initial}/Rakefile +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/Extension.coffee +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/Router.coffee +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/components/.gitkeep +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/controllers/.gitkeep +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/index.js +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/models/.gitkeep +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/models/Base.coffee +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/screens/.gitkeep +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/initial/client/appy-app/screens/Base.coffee +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/styles.scss +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/views/.gitkeep +0 -0
- data/{appy-app → spec/command-reference-files/initial}/client/appy-app/views/Base.coffee +0 -0
- data/{appy-app → spec/command-reference-files/initial}/config/database.yml +0 -0
- data/{appy-app → spec/command-reference-files/initial}/config/lanes.rb +0 -0
- data/{appy-app → spec/command-reference-files/initial}/config/routes.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/initial/config/screens.rb +0 -0
- data/{appy-app → spec/command-reference-files/initial}/config.ru +0 -0
- data/{appy-app → spec/command-reference-files/initial}/db/.gitkeep +0 -0
- data/{appy-app → spec/command-reference-files/initial}/lib/appy-app/extension.rb +0 -0
- data/{appy-app → spec/command-reference-files/initial}/lib/appy-app/model.rb +0 -0
- data/{appy-app → spec/command-reference-files/initial}/lib/appy-app/models/empty.rb +0 -0
- data/{appy-app → spec/command-reference-files/initial}/lib/appy-app/version.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/initial/lib/appy-app.rb +0 -0
- data/{appy-app → spec/command-reference-files/initial}/spec/appy-app/helpers/AppyAppHelpers.coffee +0 -0
- data/{appy-app → spec/command-reference-files/initial}/spec/appy-app/screens/Base.coffee +0 -0
- data/{appy-app → spec/command-reference-files/initial}/spec/server/spec_helpers.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/model/client/appy-app/models/TestTest.coffee +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/model/config/routes.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/model/db/migrate/20150218032025_create_test_tests.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/model/lib/appy-app/models/test_test.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/model/spec/appy-app/models/TestTestSpec.coffee +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/model/spec/fixtures/appy-app/test_test.yml +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/model/spec/server/test_test_spec.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/screen/client/appy-app/screens/ready-set-go/ReadySetGo.coffee +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/screen/client/appy-app/screens/ready-set-go/index.js +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/screen/client/appy-app/screens/ready-set-go/index.scss +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/screen/client/appy-app/screens/ready-set-go/layout.html +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/screen/config/screens.rb +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/screen/spec/appy-app/screens/ready-set-go/ReadySetGoSpec.coffee +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/view/client/appy-app/views/BigView.coffee +0 -0
- data/spec/{server/command-reference-files → command-reference-files}/view/spec/appy-app/views/BigViewSpec.coffee +0 -0
- data/spec/lanes/models/BaseSpec.coffee +4 -4
- data/spec/server/command_spec.rb +5 -1
- data/spec/server/concerns/association_extensions_spec.rb +0 -8
- data/spec/server/concerns/pub_sub_spec.rb +77 -31
- data/spec/server/spec_helper.rb +1 -0
- metadata +48 -91
- data/appy-app/client/appy-app/screens/Base.coffee +0 -10
- data/appy-app/config/screens.rb +0 -8
- data/appy-app/lib/appy-app.rb +0 -14
- data/spec/server/command-reference-files/initial/.gitignore +0 -3
- data/spec/server/command-reference-files/initial/Gemfile +0 -6
- data/spec/server/command-reference-files/initial/Guardfile +0 -13
- data/spec/server/command-reference-files/initial/Rakefile +0 -2
- data/spec/server/command-reference-files/initial/client/appy-app/Extension.coffee +0 -7
- data/spec/server/command-reference-files/initial/client/appy-app/Router.coffee +0 -4
- data/spec/server/command-reference-files/initial/client/appy-app/components/.gitkeep +0 -0
- data/spec/server/command-reference-files/initial/client/appy-app/controllers/.gitkeep +0 -0
- data/spec/server/command-reference-files/initial/client/appy-app/index.js +0 -21
- data/spec/server/command-reference-files/initial/client/appy-app/models/.gitkeep +0 -0
- data/spec/server/command-reference-files/initial/client/appy-app/models/Base.coffee +0 -5
- data/spec/server/command-reference-files/initial/client/appy-app/screens/.gitkeep +0 -0
- data/spec/server/command-reference-files/initial/client/appy-app/styles.scss +0 -1
- data/spec/server/command-reference-files/initial/client/appy-app/views/.gitkeep +0 -0
- data/spec/server/command-reference-files/initial/client/appy-app/views/Base.coffee +0 -5
- data/spec/server/command-reference-files/initial/config/database.yml +0 -9
- data/spec/server/command-reference-files/initial/config/lanes.rb +0 -7
- data/spec/server/command-reference-files/initial/config/routes.rb +0 -2
- data/spec/server/command-reference-files/initial/config.ru +0 -5
- data/spec/server/command-reference-files/initial/db/.gitkeep +0 -0
- data/spec/server/command-reference-files/initial/lib/appy-app/extension.rb +0 -13
- data/spec/server/command-reference-files/initial/lib/appy-app/model.rb +0 -11
- data/spec/server/command-reference-files/initial/lib/appy-app/models/empty.rb +0 -0
- data/spec/server/command-reference-files/initial/lib/appy-app/version.rb +0 -3
- data/spec/server/command-reference-files/initial/spec/appy-app/helpers/AppyAppHelpers.coffee +0 -5
- data/spec/server/command-reference-files/initial/spec/appy-app/screens/Base.coffee +0 -5
- data/spec/server/command-reference-files/initial/spec/server/spec_helpers.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 09c525f4869a2e1f8b1d4ff92ca1f31344715994
|
4
|
+
data.tar.gz: 98893dd650c0d95209e9b337623f1c079e807ae6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8a11e0a3028195b5cf5bf3ff6f1e2cc06754e08e776100fcc69abf330cf1cadcf1c8e8b72d408b60f73266bd719feebc0d523b4415a847957cc7f9d947ef732
|
7
|
+
data.tar.gz: a813d60b1ad735443aa90e5461743836f0eb606c81464e61e6d1131dc9e911fb5faba4a345ca876a474c3104205f360f19f1edaf0bb376bcbbe42b1f3fd56d91
|
data/.dir-locals.el
ADDED
data/client/lanes/Config.coffee
CHANGED
@@ -4,12 +4,7 @@ class Lanes.Access.Extension extends Lanes.Extensions.Base
|
|
4
4
|
|
5
5
|
setBootstrapData: (data)->
|
6
6
|
Lanes.current_user = new Lanes.Models.User
|
7
|
-
|
8
|
-
Lanes.Models.Roles.all = new Lanes.Models.Roles(
|
9
|
-
_.map( data.roles, (role)->
|
10
|
-
{ id: role.toLowerCase(), name: role }
|
11
|
-
)
|
12
|
-
)
|
7
|
+
Lanes.Models.Roles.all = new Lanes.Models.Roles( data.roles )
|
13
8
|
if data.user
|
14
9
|
Lanes.current_user.set(data.user)
|
15
10
|
if data.access
|
@@ -2,7 +2,7 @@ class Lanes.Access.Screens.UserManagement.GridUserEditor extends Lanes.Component
|
|
2
2
|
|
3
3
|
writeTemplateName: 'user-management/grid-popover-editor'
|
4
4
|
templatePrefix: 'lanes/access/screens'
|
5
|
-
|
5
|
+
useFormBindings: true
|
6
6
|
writeTemplateData: ->
|
7
7
|
{ columns: _.reject(this.grid.columnDefinitions,(f)-> f.field=='role_names') }
|
8
8
|
|
@@ -13,10 +13,11 @@ class Lanes.Access.Screens.UserManagement.GridUserEditor extends Lanes.Component
|
|
13
13
|
options: 'roleOptions'
|
14
14
|
|
15
15
|
roleOptions: ->
|
16
|
-
{
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
{
|
17
|
+
field_name: 'role_names'
|
18
|
+
multiple: true, choices: this.model.allRoles
|
19
|
+
mappings:{ title: 'name', selected: 'member' }
|
20
|
+
}
|
20
21
|
|
21
22
|
persistFields: ->
|
22
23
|
@model.set({
|
@@ -1,9 +1,9 @@
|
|
1
1
|
<form class="user-edit form-horizontal" role="form">
|
2
2
|
<% for field in @columns: %>
|
3
3
|
<div class="form-group">
|
4
|
-
<label for="field-<%= field.
|
4
|
+
<label for="field-<%= field.id %>" class="col-sm-3 control-label"><%= field.title %></label>
|
5
5
|
<div class="col-sm-9">
|
6
|
-
<input type="text" name="<%= field.
|
6
|
+
<input type="text" name="<%= field.id %>" class="form-control" id="field-<%= field.id %>" placeholder="">
|
7
7
|
</div>
|
8
8
|
</div>
|
9
9
|
<% end %>
|
@@ -2652,6 +2652,7 @@
|
|
2652
2652
|
var compat = function ( old, modern ) {
|
2653
2653
|
return json[old] !== undefined ? json[old] : json[modern];
|
2654
2654
|
};
|
2655
|
+
var data = _fnAjaxDataSrc( settings, json );
|
2655
2656
|
|
2656
2657
|
var draw = compat( 'sEcho', 'draw' );
|
2657
2658
|
var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
|
@@ -2669,7 +2670,6 @@
|
|
2669
2670
|
settings._iRecordsTotal = parseInt(recordsTotal, 10);
|
2670
2671
|
settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
|
2671
2672
|
|
2672
|
-
var data = _fnAjaxDataSrc( settings, json );
|
2673
2673
|
for ( var i=0, ien=data.length ; i<ien ; i++ ) {
|
2674
2674
|
_fnAddData( settings, data[i] );
|
2675
2675
|
}
|
@@ -26,21 +26,26 @@ class Lanes.Components.MultiSelect extends Lanes.Components.Base
|
|
26
26
|
if options.choices
|
27
27
|
@selections ||= options.choices
|
28
28
|
|
29
|
-
@selections
|
29
|
+
@selections?.ensureLoaded?()
|
30
30
|
|
31
31
|
@mappings = _.extend({
|
32
32
|
id: 'id', title: 'title', selected: 'selected'
|
33
33
|
},options.mappings||{})
|
34
34
|
|
35
|
+
unSelectAll: ->
|
36
|
+
this.$el.find(":selected").prop('selected',false)
|
35
37
|
|
36
38
|
onModelChange: ->
|
37
|
-
|
39
|
+
this.unSelectAll()
|
40
|
+
if @selections && @model
|
38
41
|
this.onModelAttributeChange(@model,@model.get(@field_name))
|
39
42
|
|
40
43
|
selectionForID: (id)->
|
41
|
-
q={}; q[@mappings.id]=
|
44
|
+
q={}; q[@mappings.id]=id
|
42
45
|
@selections.findWhere( q )
|
43
46
|
|
44
|
-
onModelAttributeChange: (model,
|
47
|
+
onModelAttributeChange: (model,fkids)->
|
45
48
|
if ! this.el.binding_is_setting
|
46
|
-
|
49
|
+
_.each(fkids, (fkid)=>
|
50
|
+
@select( @selectionForID( fkid ) )
|
51
|
+
)
|
@@ -51,6 +51,7 @@ class Lanes.Components.SelectField extends Lanes.Components.MultiSelect
|
|
51
51
|
readTemplate: ->
|
52
52
|
"<div class='ro-input' name='#{this.field_name}'></div>"
|
53
53
|
|
54
|
+
|
54
55
|
select: (option)->
|
55
56
|
if this.readOnly
|
56
57
|
this.$el.text( if option then option.code else "" )
|
@@ -59,4 +60,4 @@ class Lanes.Components.SelectField extends Lanes.Components.MultiSelect
|
|
59
60
|
option = this.query("option[value=\"#{id}\"]")
|
60
61
|
option.selected = true
|
61
62
|
else
|
62
|
-
this
|
63
|
+
this.unSelectAll()
|
@@ -9,7 +9,7 @@ class ModelType extends Lanes.Models.State
|
|
9
9
|
records: 'object'
|
10
10
|
|
11
11
|
subscribe: (model)->
|
12
|
-
channel = "/#{model
|
12
|
+
channel = "/#{_.result(model,'api_path')}/#{model.id}"
|
13
13
|
Lanes.Vendor.MessageBus.subscribe(channel,(changes)->
|
14
14
|
model.addChangeSet(changes)
|
15
15
|
)
|
@@ -33,7 +33,8 @@ class ModelTypesCollection extends Lanes.Models.BasicCollection
|
|
33
33
|
model: ModelType
|
34
34
|
|
35
35
|
forModel: (model)->
|
36
|
-
|
36
|
+
path = _.result(model,'api_path')
|
37
|
+
models = this.get(path) || this.add(id: path)
|
37
38
|
|
38
39
|
|
39
40
|
Lanes.Models.PubSub = {
|
@@ -51,7 +52,7 @@ Lanes.Models.PubSub = {
|
|
51
52
|
@types.forModel(model).remove(model)
|
52
53
|
|
53
54
|
instanceFor: ( model_klass, id )->
|
54
|
-
@types.get(model_klass.prototype
|
55
|
+
@types.get(_.result(model_klass.prototype,'api_path'))?.records[id]?.model
|
55
56
|
|
56
57
|
clear: ->
|
57
58
|
@types = new ModelTypesCollection
|
@@ -77,9 +77,9 @@ Lanes.Models.Sync = {
|
|
77
77
|
# Ensure that we have a URL.
|
78
78
|
params.url = _.result(model, "url") or Lanes.Models.Sync.urlError() unless options.url
|
79
79
|
params.url += '.json'
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
|
81
|
+
params.headers = _.extend({}, _.result(options,'headers'))
|
82
|
+
params.headers['X_CSRF_TOKEN'] = Lanes.config.csrf_token
|
83
83
|
params.contentType = "application/json"
|
84
84
|
if options.data || _.contains(['create','update','patch'], method)
|
85
85
|
params.data = JSON.stringify( options.data || model.dataForSave(options) )
|
@@ -1,14 +1,21 @@
|
|
1
1
|
class Lanes.Testing.ModelSaver
|
2
2
|
|
3
|
+
@setUser: (login)->
|
4
|
+
Lanes.Testing.ModelSaver::headers['X_TESTING_USER']= login
|
5
|
+
|
3
6
|
@perform: (model,completion)->
|
4
7
|
saver = new Lanes.Testing.ModelSaver(completion)
|
5
8
|
saver.save(model)
|
6
9
|
|
10
|
+
headers:
|
11
|
+
X_ROLLBACK_AFTER_REQUEST: true
|
12
|
+
|
7
13
|
constructor: (@completion)->
|
8
14
|
_.bindAll(this,'success','error')
|
9
15
|
spyOn(this, 'success').and.callThrough()
|
10
16
|
spyOn(this, 'error').and.callThrough()
|
11
17
|
|
18
|
+
|
12
19
|
success: ->
|
13
20
|
this.notification.resolve(this)
|
14
21
|
_.defer(@completion) if @completion
|
@@ -18,6 +25,10 @@ class Lanes.Testing.ModelSaver
|
|
18
25
|
_.defer(@completion) if @completion
|
19
26
|
|
20
27
|
save: (model)->
|
21
|
-
model.save(this)
|
28
|
+
model.save(this.toOptions()).then(Lanes.emptyFn, Lanes.emptyFn)
|
22
29
|
this.notification = new _.DeferredPromise
|
23
30
|
this.notification.promise
|
31
|
+
|
32
|
+
|
33
|
+
toOptions: ->
|
34
|
+
_.pick(this,'headers','success','error')
|
@@ -369,7 +369,7 @@ class ViewBase
|
|
369
369
|
prev = this.previous('model')
|
370
370
|
return if prev == @model
|
371
371
|
this._unbindFromObject(prev, @modelEvents) if prev
|
372
|
-
this._bindToObject(@model, @modelEvents)
|
372
|
+
this._bindToObject(@model, @modelEvents) if @model
|
373
373
|
this.onModelChange?()
|
374
374
|
true
|
375
375
|
|
@@ -57,8 +57,9 @@ Lanes.Views.Helpers = {
|
|
57
57
|
impl.grid_widths(widths);
|
58
58
|
|
59
59
|
text_field: (name,options={})->
|
60
|
+
value = if options.value then " value=#{options.value}" else ''
|
60
61
|
impl.field(name, options,
|
61
|
-
"<input type='#{options.type || 'text'}' name='#{name}'
|
62
|
+
"<input type='#{options.type || 'text'}' name='#{name}'#{value}><span class='feedback'></span>"
|
62
63
|
"<div class='ro-input update' name='#{name}'></div>"
|
63
64
|
)
|
64
65
|
|
@@ -1,26 +1,27 @@
|
|
1
|
-
|
2
1
|
class ModelSaver
|
3
2
|
|
4
3
|
constructor: ( @element, @options )->
|
5
4
|
@mask = new Lanes.Views.TimedMask( @element, @options.message )
|
6
5
|
@mask.prefixActions( "Save" )
|
7
6
|
_.bindAll(this,'_onError','_onSuccess')
|
7
|
+
this.notification = new _.DeferredPromise
|
8
8
|
|
9
9
|
save: ->
|
10
10
|
@options.model.save({
|
11
11
|
success: this._onSuccess, error: this._onError
|
12
12
|
})
|
13
13
|
|
14
|
-
_onSuccess: (
|
14
|
+
_onSuccess: (data,success,resp)->
|
15
15
|
@mask.displaySuccess()
|
16
|
-
this._callback(true,resp)
|
16
|
+
this._callback(true,data,resp)
|
17
17
|
|
18
|
-
_onError: (
|
19
|
-
@mask.displayFailure(
|
20
|
-
this._callback(false,resp)
|
18
|
+
_onError: (data,success,resp)->
|
19
|
+
@mask.displayFailure(@options.model.lastServerMessage)
|
20
|
+
this._callback(false,data,resp)
|
21
21
|
|
22
|
-
_callback: (success,resp)->
|
22
|
+
_callback: (success,data,resp)->
|
23
23
|
@options.callback(success,resp,@options.model) if @options.callback
|
24
|
+
this.notification?.resolve(data: data.data, success: success, response: resp)
|
24
25
|
|
25
26
|
|
26
27
|
Lanes.Views.SaveNotify = ( view, options={} )->
|
@@ -28,3 +29,4 @@ Lanes.Views.SaveNotify = ( view, options={} )->
|
|
28
29
|
_.defaults( options, { model: view.model, message: "Saving, Please Wait…"} )
|
29
30
|
ms = new ModelSaver(el, options)
|
30
31
|
ms.save()
|
32
|
+
return ms.notification.promise
|
data/lanes.gemspec
CHANGED
@@ -53,6 +53,6 @@ Gem::Specification.new do |spec|
|
|
53
53
|
spec.add_dependency "sanitize", "~> 3.0"
|
54
54
|
spec.add_development_dependency "bundler", "~> 1.5"
|
55
55
|
spec.add_development_dependency "growl", "~> 1.0"
|
56
|
-
spec.add_development_dependency "pry-byebug", "~> 2.0"
|
57
56
|
spec.add_development_dependency "diffy", "~> 3.0"
|
57
|
+
|
58
58
|
end
|
@@ -2,14 +2,20 @@ module Lanes
|
|
2
2
|
module API
|
3
3
|
class AuthenticationProvider
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@
|
5
|
+
attr_reader :request
|
6
|
+
|
7
|
+
def initialize(request)
|
8
|
+
@request=request
|
9
9
|
end
|
10
10
|
|
11
11
|
def current_user
|
12
|
-
@current_user ||=
|
12
|
+
@current_user ||= (
|
13
|
+
if Lanes.env.test? && request.env['HTTP_X_TESTING_USER']
|
14
|
+
Lanes::User.where(login: request.env['HTTP_X_TESTING_USER']).first
|
15
|
+
else
|
16
|
+
Lanes::User.where(id: @session['user_id']).first
|
17
|
+
end
|
18
|
+
)
|
13
19
|
end
|
14
20
|
|
15
21
|
def error_message
|
@@ -17,7 +23,7 @@ module Lanes
|
|
17
23
|
end
|
18
24
|
|
19
25
|
def error_message_for_access
|
20
|
-
return "Unable to " + case @
|
26
|
+
return "Unable to " + case @request.request_method
|
21
27
|
when 'GET' then "read"
|
22
28
|
when 'POST','PATCH','PUT' then "write"
|
23
29
|
when 'DELETE' then "delete"
|
@@ -28,20 +34,20 @@ module Lanes
|
|
28
34
|
|
29
35
|
def allowed_access_to?(klass)
|
30
36
|
return false if current_user.nil?
|
31
|
-
case @
|
37
|
+
case @request.request_method
|
32
38
|
when 'GET'
|
33
|
-
klass.can_read_attributes?(@params,current_user)
|
39
|
+
klass.can_read_attributes?(@request.params,current_user)
|
34
40
|
when 'POST','PATCH','PUT'
|
35
|
-
klass.can_write_attributes?(@params,current_user)
|
41
|
+
klass.can_write_attributes?(@request.params,current_user)
|
36
42
|
when 'DELETE'
|
37
|
-
klass.can_delete_attributes?(@params,current_user)
|
43
|
+
klass.can_delete_attributes?(@request.params,current_user)
|
38
44
|
else
|
39
45
|
false
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
43
49
|
|
44
|
-
def
|
50
|
+
def wrap_reply(model, req)
|
45
51
|
if allowed_access_to?(model)
|
46
52
|
::Lanes::User.scoped_to(current_user) do | user |
|
47
53
|
yield
|
@@ -25,9 +25,16 @@ module Lanes
|
|
25
25
|
def client_paths
|
26
26
|
[]
|
27
27
|
end
|
28
|
-
|
28
|
+
def roles_for_client
|
29
|
+
Lanes::Access::Role.all_available.map do |role|
|
30
|
+
{
|
31
|
+
id: role.to_s.demodulize.underscore,
|
32
|
+
name: role.to_s.demodulize
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
29
36
|
def client_bootstrap_data(view)
|
30
|
-
data = {}
|
37
|
+
data = { roles: roles_for_client }
|
31
38
|
if (user_id = view.session['user_id']) && (user = Lanes::User.where( id: user_id ).first)
|
32
39
|
data.merge!(user.workspace_data)
|
33
40
|
end
|
data/lib/lanes/access/role.rb
CHANGED
@@ -41,6 +41,18 @@ module Lanes
|
|
41
41
|
delete.push( *klasses )
|
42
42
|
end
|
43
43
|
|
44
|
+
def read( *klasses )
|
45
|
+
self.read.push( *klasses )
|
46
|
+
end
|
47
|
+
|
48
|
+
def write( *klasses )
|
49
|
+
self.write.push( *klasses )
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete( *klasses )
|
53
|
+
self.delete.push( *klasses )
|
54
|
+
end
|
55
|
+
|
44
56
|
def lock(klass, attribute)
|
45
57
|
LockedFields.lock( klass, attribute, self)
|
46
58
|
end
|
data/lib/lanes/access.rb
CHANGED
@@ -6,11 +6,11 @@ module Lanes
|
|
6
6
|
|
7
7
|
class << self
|
8
8
|
|
9
|
-
def
|
9
|
+
def type_to_client(klass)
|
10
10
|
klass.to_s.sub(/^(\w+).*?(\w+)$/,'\1.Models.\2')
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
13
|
+
def type_to_client_id(klass)
|
14
14
|
( klass.is_a?(Class) ? klass : klass.class ).to_s.demodulize.underscore
|
15
15
|
end
|
16
16
|
|
@@ -18,18 +18,18 @@ module Lanes
|
|
18
18
|
{
|
19
19
|
:roles => user.roles.map{ | role |
|
20
20
|
{
|
21
|
-
type:
|
22
|
-
read: role.read.map{ |klass|
|
23
|
-
write: role.write.map{ |klass|
|
24
|
-
delete: role.delete.map{ |klass|
|
21
|
+
type: type_to_client_id(role),
|
22
|
+
read: role.read.map{ |klass| type_to_client(klass) },
|
23
|
+
write: role.write.map{ |klass| type_to_client(klass) },
|
24
|
+
delete: role.delete.map{ |klass| type_to_client(klass) }
|
25
25
|
}
|
26
26
|
},
|
27
27
|
:locked_fields => LockedFields.definitions.map{ | klass, locks |
|
28
28
|
{
|
29
|
-
type:
|
29
|
+
type: type_to_client(klass),
|
30
30
|
locks: locks.each_with_object({}) do |(field, grants), result|
|
31
31
|
result[field] = grants.map do |grant|
|
32
|
-
{ role:
|
32
|
+
{ role: type_to_client_id(grant[:role]), only: grant[:only] }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
}
|
@@ -17,14 +17,14 @@ module Lanes
|
|
17
17
|
class AuthenticationProvider
|
18
18
|
USER = DummyUser.new
|
19
19
|
|
20
|
-
def initialize(
|
20
|
+
def initialize(request)
|
21
21
|
end
|
22
22
|
|
23
23
|
def current_user
|
24
24
|
USER
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
27
|
+
def wrap_reply(model, req)
|
28
28
|
yield
|
29
29
|
end
|
30
30
|
|
@@ -30,17 +30,13 @@ module Lanes
|
|
30
30
|
|
31
31
|
def make_handler(model, controller, parent_attribute)
|
32
32
|
lambda do
|
33
|
-
authentication = Lanes::API::AuthenticationProvider.new(
|
34
|
-
|
35
|
-
session: session,
|
36
|
-
params: params
|
37
|
-
)
|
38
|
-
authentication.wrap_request(model,self) do
|
33
|
+
authentication = Lanes::API::AuthenticationProvider.new(request)
|
34
|
+
authentication.wrap_reply(model,self) do
|
39
35
|
if parent_attribute
|
40
36
|
params[:nested_attribute] = Hash[ parent_attribute,
|
41
37
|
params[parent_attribute] ]
|
42
38
|
end
|
43
|
-
|
39
|
+
wrap_reply(!request.get?) do
|
44
40
|
yield controller.new(model, authentication, params, data)
|
45
41
|
end
|
46
42
|
end
|
@@ -52,13 +48,17 @@ module Lanes
|
|
52
48
|
Lanes.logger.info "UserID: #{session['user_id']}, Params: #{request.params}"
|
53
49
|
end
|
54
50
|
|
55
|
-
def
|
51
|
+
def wrap_reply(with_transaction=true)
|
56
52
|
response = { success: false, message: "No response was generated" }
|
57
53
|
log_request
|
58
54
|
if with_transaction
|
59
55
|
Lanes::Model.transaction do
|
60
|
-
|
61
|
-
|
56
|
+
response = yield
|
57
|
+
# This is quite possibly a horrible idea.
|
58
|
+
# It enables test specs to reset the db state after a request
|
59
|
+
if Lanes.env.test? && request.env['HTTP_X_ROLLBACK_AFTER_REQUEST']
|
60
|
+
Lanes::Model.connection.rollback_db_transaction
|
61
|
+
end
|
62
62
|
end
|
63
63
|
else
|
64
64
|
response = yield
|
@@ -59,22 +59,31 @@ module Lanes::Concerns
|
|
59
59
|
"an inverse_of specified."
|
60
60
|
end
|
61
61
|
listeners.each do | name, target |
|
62
|
-
targets[
|
63
|
-
record = record.send( association.inverse_of.name )
|
64
|
-
record.send( target, *( [record] + args ) ) if record
|
65
|
-
}
|
62
|
+
targets[name] = make_association_listener_for(target, association)
|
66
63
|
end
|
67
64
|
begin
|
68
65
|
klass = association.klass # This will throw if the class hasn't been loaded yet
|
69
|
-
targets.each{ | name, proc | klass._add_event_listener( name, proc ) }
|
66
|
+
targets.each{ | name, proc | klass._add_event_listener( name, &proc ) }
|
70
67
|
rescue NameError
|
71
|
-
pending =
|
68
|
+
pending = Lanes::Concerns::PubSub::PendingListeners.add(association.class_name)
|
72
69
|
targets.each do | name, proc |
|
73
70
|
pending[name] << proc
|
74
71
|
end
|
75
72
|
end
|
76
73
|
end
|
77
|
-
|
74
|
+
def make_association_listener_for(target, association)
|
75
|
+
Proc.new{ | record, *args |
|
76
|
+
associated_record = record.public_send(association.inverse_of.name)
|
77
|
+
if associated_record
|
78
|
+
args.unshift(record)
|
79
|
+
if associated_record.is_a? ActiveRecord::Associations::CollectionProxy
|
80
|
+
associated_record.each{ |r| r.send(target, *args) }
|
81
|
+
else
|
82
|
+
associated_record.send(target, *args)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
}
|
86
|
+
end
|
78
87
|
def setup_association_export( association, options )
|
79
88
|
export_associations( association.name, options == true ? {} : options )
|
80
89
|
end
|