2018-09-11 15:08:34 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-12-11 09:21:06 -05:00
|
|
|
module FinderMethods
|
2018-08-27 11:31:01 -04:00
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
2017-12-11 09:21:06 -05:00
|
|
|
def find_by!(*args)
|
2019-02-20 06:31:06 -05:00
|
|
|
raise_not_found_unless_authorized execute.reorder(nil).find_by!(*args)
|
2017-12-11 09:21:06 -05:00
|
|
|
end
|
2018-08-27 11:31:01 -04:00
|
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
2017-12-11 09:21:06 -05:00
|
|
|
|
2018-08-27 11:31:01 -04:00
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
2017-12-11 09:21:06 -05:00
|
|
|
def find_by(*args)
|
2019-02-20 06:31:06 -05:00
|
|
|
if_authorized execute.reorder(nil).find_by(*args)
|
2017-12-11 09:21:06 -05:00
|
|
|
end
|
2018-08-27 11:31:01 -04:00
|
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
2017-12-11 09:21:06 -05:00
|
|
|
|
|
|
|
def find(*args)
|
|
|
|
raise_not_found_unless_authorized model.find(*args)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def raise_not_found_unless_authorized(result)
|
|
|
|
result = if_authorized(result)
|
|
|
|
|
|
|
|
raise ActiveRecord::RecordNotFound.new("Couldn't find #{model}") unless result
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def if_authorized(result)
|
|
|
|
# Return the result if the finder does not perform authorization checks.
|
|
|
|
# this is currently the case in the `MilestoneFinder`
|
2020-08-27 14:10:29 -04:00
|
|
|
return result unless respond_to?(:current_user, true)
|
2017-12-11 09:21:06 -05:00
|
|
|
|
|
|
|
if can_read_object?(result)
|
|
|
|
result
|
|
|
|
else
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_read_object?(object)
|
|
|
|
# When there's no policy, we'll allow the read, this is for example the case
|
|
|
|
# for Todos
|
|
|
|
return true unless DeclarativePolicy.has_policy?(object)
|
|
|
|
|
2020-08-27 14:10:29 -04:00
|
|
|
Ability.allowed?(current_user, :"read_#{to_ability_name(object)}", object)
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_ability_name(object)
|
|
|
|
return object.to_ability_name if object.respond_to?(:to_ability_name)
|
2017-12-11 09:21:06 -05:00
|
|
|
|
2020-08-27 14:10:29 -04:00
|
|
|
# Not all objects define `#to_ability_name`, so attempt to derive it:
|
|
|
|
object.model_name.singular
|
2017-12-11 09:21:06 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
# This fetches the model from the `ActiveRecord::Relation` but does not
|
|
|
|
# actually execute the query.
|
|
|
|
def model
|
|
|
|
execute.model
|
|
|
|
end
|
|
|
|
end
|