Skip to content

Commit a222222

Browse files
committed
closes #102 #99
1 parent 77aac1b commit a222222

File tree

21 files changed

+315
-104
lines changed

21 files changed

+315
-104
lines changed

install/rails-webpacker.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,14 @@ class ApplicationRecord < ActiveRecord::Base
7373
7474
# useful for debugging
7575
module Hyperstack
76-
def self.on_error(*args)
77-
::Rails.logger.debug "\033[0;31;1mHYPERSTACK APPLICATION ERROR: #{args.join(", ")}\n"\\
78-
"To further investigate you may want to add a debugging "\\
79-
"breakpoint in config/initializers/hyperstack.rb\033[0;30;21m"
76+
def self.on_error(operation, err, params, formatted_error_message)
77+
::Rails.logger.debug(
78+
"#{formatted_error_message}\n\n" +
79+
Pastel.new.red(
80+
'To further investigate you may want to add a debugging '\
81+
'breakpoint to the on_error method in config/initializers/hyperstack.rb'
82+
)
83+
)
8084
end
8185
end if Rails.env.development?
8286
CODE

ruby/hyper-model/Gemfile.lock

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
PATH
22
remote: ../hyper-component
33
specs:
4-
hyper-component (1.0.alpha1.1)
5-
hyper-state (= 1.0.alpha1.1)
6-
hyperstack-config (= 1.0.alpha1.1)
4+
hyper-component (1.0.alpha1.2)
5+
hyper-state (= 1.0.alpha1.2)
6+
hyperstack-config (= 1.0.alpha1.2)
77
libv8 (~> 6.3.0)
88
mini_racer (~> 0.1.15)
99
opal (>= 0.11.0, < 0.12.0)
@@ -13,23 +13,24 @@ PATH
1313
PATH
1414
remote: ../hyper-operation
1515
specs:
16-
hyper-operation (1.0.alpha1.1)
16+
hyper-operation (1.0.alpha1.2)
1717
activerecord (>= 4.0.0)
18-
hyper-component (= 1.0.alpha1.1)
18+
hyper-component (= 1.0.alpha1.2)
1919
mutations
2020
opal-activesupport (~> 0.3.1)
21+
tty-table
2122

2223
PATH
2324
remote: ../hyper-state
2425
specs:
25-
hyper-state (1.0.alpha1.1)
26-
hyperstack-config (= 1.0.alpha1.1)
26+
hyper-state (1.0.alpha1.2)
27+
hyperstack-config (= 1.0.alpha1.2)
2728
opal (>= 0.11.0, < 0.12.0)
2829

2930
PATH
3031
remote: ../hyperstack-config
3132
specs:
32-
hyperstack-config (1.0.alpha1.1)
33+
hyperstack-config (1.0.alpha1.2)
3334
libv8 (~> 6.3.0)
3435
listen (~> 3.0)
3536
mini_racer (~> 0.1.15)
@@ -41,11 +42,11 @@ PATH
4142
PATH
4243
remote: .
4344
specs:
44-
hyper-model (1.0.alpha1.1)
45+
hyper-model (1.0.alpha1.2)
4546
activemodel
4647
activerecord (>= 4.0.0)
47-
hyper-component (= 1.0.alpha1.1)
48-
hyper-operation (= 1.0.alpha1.1)
48+
hyper-component (= 1.0.alpha1.2)
49+
hyper-operation (= 1.0.alpha1.2)
4950

5051
GEM
5152
remote: https://rubygems.org/
@@ -141,6 +142,7 @@ GEM
141142
eventmachine (>= 0.12.9)
142143
http_parser.rb (~> 0.6.0)
143144
equalizer (0.0.11)
145+
equatable (0.5.0)
144146
erubi (1.7.1)
145147
eventmachine (1.2.7)
146148
execjs (2.7.0)
@@ -189,6 +191,7 @@ GEM
189191
mutations (0.8.3)
190192
activesupport
191193
mysql2 (0.5.2)
194+
necromancer (0.4.0)
192195
nio4r (2.3.1)
193196
nokogiri (1.8.4)
194197
mini_portile2 (~> 2.3.0)
@@ -220,6 +223,9 @@ GEM
220223
parallel (1.12.1)
221224
parser (2.3.3.1)
222225
ast (~> 2.2)
226+
pastel (0.7.2)
227+
equatable (~> 0.5.0)
228+
tty-color (~> 0.4.0)
223229
powerpack (0.1.2)
224230
procto (0.0.3)
225231
pry (0.11.3)
@@ -271,8 +277,8 @@ GEM
271277
rake
272278
rake (12.3.1)
273279
rb-fsevent (0.10.3)
274-
rb-inotify (0.9.10)
275-
ffi (>= 0.5.0, < 2)
280+
rb-inotify (0.10.0)
281+
ffi (~> 1.0)
276282
react-rails (2.4.7)
277283
babel-transpiler (>= 0.7.0)
278284
connection_pool
@@ -343,6 +349,11 @@ GEM
343349
activesupport (>= 4.0)
344350
sprockets (>= 3.0.0)
345351
sqlite3 (1.3.13)
352+
strings (0.1.4)
353+
strings-ansi (~> 0.1.0)
354+
unicode-display_width (~> 1.4.0)
355+
unicode_utils (~> 1.4.0)
356+
strings-ansi (0.1.0)
346357
thin (1.7.2)
347358
daemons (~> 1.0, >= 1.0.9)
348359
eventmachine (~> 1.0, >= 1.0.4)
@@ -351,11 +362,20 @@ GEM
351362
thread_safe (0.3.6)
352363
tilt (2.0.8)
353364
timecop (0.8.1)
365+
tty-color (0.4.3)
366+
tty-screen (0.6.5)
367+
tty-table (0.10.0)
368+
equatable (~> 0.5.0)
369+
necromancer (~> 0.4.0)
370+
pastel (~> 0.7.2)
371+
strings (~> 0.1.0)
372+
tty-screen (~> 0.6.4)
354373
tzinfo (1.2.5)
355374
thread_safe (~> 0.1)
356-
uglifier (4.1.19)
375+
uglifier (4.1.20)
357376
execjs (>= 0.3.0, < 3)
358377
unicode-display_width (1.4.0)
378+
unicode_utils (1.4.0)
359379
unparser (0.2.8)
360380
abstract_type (~> 0.0.7)
361381
adamantium (~> 0.2.0)

ruby/hyper-model/lib/active_record_base.rb

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def self._synchromesh_scope_args_check(args)
2929
class ReactiveRecordPsuedoRelationArray < Array
3030
attr_accessor :__synchromesh_permission_granted
3131
attr_accessor :acting_user
32-
def __secure_collection_check(_acting_user)
32+
def __secure_collection_check(*)
3333
self
3434
end
3535
end
@@ -39,11 +39,13 @@ def __secure_collection_check(_acting_user)
3939
class Relation
4040
attr_accessor :__synchromesh_permission_granted
4141
attr_accessor :acting_user
42-
def __secure_collection_check(acting_user)
42+
43+
def __secure_collection_check(cache_item)
4344
return self if __synchromesh_permission_granted
44-
return self if __secure_remote_access_to_all(self, acting_user).__synchromesh_permission_granted
45-
return self if __secure_remote_access_to_unscoped(self, acting_user).__synchromesh_permission_granted
46-
Hyperstack::InternalPolicy.raise_operation_access_violation(:scoped_permission_not_granted, "Last relation: #{self}, acting_user: #{acting_user}")
45+
return self if __secure_remote_access_to_all(self, cache_item.acting_user).__synchromesh_permission_granted
46+
return self if __secure_remote_access_to_unscoped(self, cache_item.acting_user).__synchromesh_permission_granted
47+
Hyperstack::InternalPolicy.raise_operation_access_violation(
48+
:scoped_permission_not_granted, "Access denied for #{cache_item}")
4749
end
4850
end
4951
# Monkey patches and extensions to base
@@ -90,6 +92,9 @@ def finder_method(name, &block)
9092
this.acting_user = old
9193
end
9294
end
95+
singleton_class.send(:define_method, "_#{name}") do |*args|
96+
all.instance_exec(*args, &block)
97+
end
9398
singleton_class.send(:define_method, name) do |*args|
9499
all.instance_exec(*args, &block)
95100
end

ruby/hyper-model/lib/reactive_record/active_record/class_methods.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,10 @@ def unscoped
261261
end
262262

263263
def finder_method(name)
264-
ReactiveRecord::ScopeDescription.new(self, "_#{name}", {})
264+
ReactiveRecord::ScopeDescription.new(self, "_#{name}", {}) # was adding _ to front
265265
[name, "#{name}!"].each do |method|
266266
singleton_class.send(:define_method, method) do |*vargs|
267-
all.apply_scope("_#{method}", *vargs).first
267+
all.apply_scope("_#{method}", *vargs).first # was adding _ to front
268268
end
269269
end
270270
end

ruby/hyper-model/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -316,21 +316,23 @@ def send_save_to_server(save, validate, force, &block)
316316

317317
else
318318

319-
def self.find_record(model, id, vector, save)
319+
def self.find_record(model, id, acting_user, vector, save)
320320
if !save
321321
found = vector[1..-1].inject(vector[0]) do |object, method|
322322
if object.nil? # happens if you try to do an all on empty scope followed by more scopes
323323
object
324-
elsif method.is_a? Array
324+
elsif method.is_a? Array #__secure_remote_access_to_
325325
if method[0] == 'new'
326326
object.new
327-
else
327+
elsif method[0] == 'find_by'
328328
object.send(*method)
329+
else
330+
object.send(:"__secure_remote_access_to_#{method[0]}", object, acting_user, *method[1..-1])
329331
end
330-
elsif method.is_a? String and method[0] == '*'
332+
elsif method.is_a?(String) && method[0] == '*'
331333
object[method.gsub(/^\*/,'').to_i]
332334
else
333-
object.send(method)
335+
object.send(:"__secure_remote_access_to_#{method}", object, acting_user)
334336
end
335337
end
336338
if id and (found.nil? or !(found.class <= model) or (found.id and found.id.to_s != id.to_s))
@@ -362,13 +364,13 @@ def self.save_records(models, associations, acting_user, validate, save)
362364
id = attributes.delete(model.primary_key) if model.respond_to? :primary_key # if we are saving existing model primary key value will be present
363365
vector = model_to_save[:vector]
364366
vector = [vector[0].constantize] + vector[1..-1].collect do |method|
365-
if method.is_a?(Array) and method.first == "find_by_id"
367+
if method.is_a?(Array) && method.first == "find_by_id"
366368
["find", method.last]
367369
else
368370
method
369371
end
370372
end
371-
reactive_records[model_to_save[:id]] = vectors[vector] = record = find_record(model, id, vector, save) # ??? || validate ???
373+
reactive_records[model_to_save[:id]] = vectors[vector] = record = find_record(model, id, acting_user, vector, save) # ??? || validate ???
372374
next unless record
373375
if attributes.empty?
374376
dont_save_list << record unless save
@@ -507,7 +509,7 @@ def self.save_records(models, associations, acting_user, validate, save)
507509
if save || validate
508510
{success: false, saved_models: saved_models, message: e}
509511
else
510-
{}
512+
raise e # was returning {} TODO verify that just raising the error at least reports the error
511513
end
512514
end
513515

ruby/hyper-model/lib/reactive_record/active_record/reactive_record/operations.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ class Fetch < Base
6565
]
6666
end
6767
failed do |e|
68-
# AccessViolations are already sent to on_error
69-
Hyperstack.on_error(e, :fetch_error, params.to_h) unless e.is_a? Hyperstack::AccessViolation
68+
e.define_singleton_method(:__hyperstack_on_error) do |operation, params, fmted_message|
69+
Hyperstack.on_error(operation, self, params, fmted_message)
70+
end
7071
raise e
7172
end
7273
end

ruby/hyper-model/lib/reactive_record/permissions.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class << self
9090
def belongs_to(attr_name, *args)
9191
belongs_to_without_reactive_record_add_is_method(attr_name, *args).tap do
9292
define_method "#{attr_name}_is?".to_sym do |model|
93-
self.class.reflections[attr_name].foreign_key == model.id
93+
self.class.reflections[attr_name.to_s].foreign_key == model.id
9494
end
9595
end
9696
end
@@ -103,7 +103,19 @@ def check_permission_with_acting_user(user, permission, *args)
103103
self.acting_user = old
104104
self
105105
else
106-
Hyperstack::InternalPolicy.raise_operation_access_violation(:crud_access_violation, "for #{self} - #{permission}(#{args}) acting_user: #{user}")
106+
acting_user_string =
107+
if acting_user
108+
id = user.respond_to?(:id) ? user.id : user
109+
"not allowed for acting_user: <##{user.class} id: #{user}>"
110+
else
111+
"not allowed without acting_user (acting_user = nil)"
112+
end
113+
114+
message = "CRUD access violation: <##{self.class} id: #{self.id}> - #{permission}(#{args}) #{acting_user_string}"
115+
if permission == :view_permitted?
116+
details = Hyperstack::PolicyDiagnostics.policy_dump_for(self, user)
117+
end
118+
Hyperstack::InternalPolicy.raise_operation_access_violation(message, details || '')
107119
end
108120
end
109121

ruby/hyper-model/lib/reactive_record/server_data_cache.rb

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,26 @@ def initialize(db_cache, acting_user, klass, preloaded_records)
229229
@db_cache.add_item_to_cache self
230230
end
231231

232+
def to_s
233+
acting_user_string =
234+
if acting_user
235+
" - with acting user: <#{acting_user.class.name} id: #{acting_user.id}>"
236+
else
237+
' - with no acting user'
238+
end
239+
vector.collect do |e|
240+
if e.is_a? String
241+
e
242+
elsif e.is_a? Array
243+
e.length > 1 ? "#{e.first}(#{e[1..-1].join(', ')})" : e.first
244+
else
245+
e.name
246+
end
247+
end.join('.') + acting_user_string
248+
rescue
249+
vector.to_s + acting_user_string
250+
end
251+
232252
def start_timing(&block)
233253
ServerDataCache.class.start_timing(&block)
234254
end
@@ -245,11 +265,11 @@ def apply_method_to_cache(method)
245265
cache_item.apply_star || representative
246266
elsif method == "*all"
247267
# if we secure the collection then we assume its okay to read the ids
248-
secured_value = cache_item.value.__secure_collection_check(@acting_user)
268+
secured_value = cache_item.value.__secure_collection_check(cache_item)
249269
cache_item.build_new_cache_item(timing(:active_record) { secured_value.collect { |record| record.id } }, method, method)
250270
elsif method == "*count"
251-
secured_value = cache_item.value.__secure_collection_check(@acting_user)
252-
cache_item.build_new_cache_item(timing(:active_record) { cache_item.value.__secure_collection_check(@acting_user).count }, method, method)
271+
secured_value = cache_item.value.__secure_collection_check(cache_item)
272+
cache_item.build_new_cache_item(timing(:active_record) { cache_item.value.__secure_collection_check(cache_item).count }, method, method)
253273
elsif preloaded_value = @preloaded_records[cache_item.absolute_vector + [method]]
254274
# no security check needed since we already evaluated this
255275
cache_item.build_new_cache_item(preloaded_value, method, method)
@@ -273,10 +293,10 @@ def apply_method_to_cache(method)
273293
else
274294
raise "method missing"
275295
end
276-
rescue Exception => e # this check may no longer be needed as we are quite explicit now on which methods we apply
277-
# ReactiveRecord::Pry::rescued(e)
278-
::Rails.logger.debug "\033[0;31;1mERROR: HyperModel exception caught when applying #{method} to db object #{cache_item.value}: #{e}\033[0;30;21m"
279-
raise e, "HyperModel fetching records failed, exception caught when applying #{method} to db object #{cache_item.value}: #{e}", e.backtrace
296+
# rescue Exception => e # this check may no longer be needed as we are quite explicit now on which methods we apply
297+
# # ReactiveRecord::Pry::rescued(e)
298+
# #::Rails.logger.debug "\033[0;31;1mERROR: HyperModel exception caught when applying #{method} to db object #{cache_item.value}: #{e}\033[0;30;21m"
299+
# raise e, "HyperModel fetching records failed, exception caught when applying #{method} to db object #{cache_item.value}: #{e}", e.backtrace
280300
end
281301
end
282302
end
@@ -296,7 +316,7 @@ def aggregation?(method)
296316
end
297317

298318
def apply_star
299-
if @value && @value.__secure_collection_check(@acting_user) && @value.length > 0
319+
if @value && @value.__secure_collection_check(self) && @value.length > 0
300320
i = -1
301321
@value.inject(nil) do |representative, current_value|
302322
i += 1

0 commit comments

Comments
 (0)