-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
data filtering for rails backend #16
Conversation
role in actor.org_roles and | ||
role_name = role.name and | ||
resource = role.org; | ||
resource.id = role.org_id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did it not work with resource = role.org
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, somehow it hit one of the unimplemented paths in the core
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you created a task for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will once I find a minimal repro 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did this happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping @GW000
repo_id: Integer, | ||
user_id: Integer, | ||
name: String, | ||
repo: Relationship.new( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any way to build these relationships automatically from the activerecord associations? 😬
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally fine if that's out of scope, just kind of curious
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that sure would be nice, this is a lot of boilerplate!
orgs = Org.all | ||
orgs = orgs.filter { |org| OSO.allowed?(actor: current_user, action: "read", resource: org) } | ||
render json: orgs | ||
render json: OSO.get_allowed_resources(current_user, 'read', Org) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the only place we actually use data filtering
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add it to the repos index too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the repos index is populated based on org ownership though, not user permissions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add another view I guess that shows all the repos for the current user
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's probably worth doing anyway -- it's a good way of showing how data filtering is doing something more than a simple filter.
But even if repos are filtered by org, you might want to apply data filtering. For example, in GitHub you have public + private org repos that you can see or not depending on whether you're a member of the org.
That's not the case in the current gitclub, but is rationale for why you would still apply authorization to the org_repos index.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok the new view is in, it's a good example for data filtering because it shows repos from any org. As it is only org members can view the org repos index so the authorization is already implicit there. The current data filtering API isn't a good fit here unfortunately, you'd need to get the repos the user can read, then filter it again to select the ones belonging to the org.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reflexively pressed the big green button and am not qualified to review my own code 👍
@@ -5,7 +5,7 @@ class ApplicationController < ActionController::API | |||
rescue_from Exceptions::Forbidden, with: :render_forbidden | |||
|
|||
def authorize!(action, resource, error=Exceptions::NotFound) | |||
raise error unless OSO.allowed?(actor: current_user, action: action, resource: resource) | |||
raise error unless OSO.allowed?(actor: current_user, action: action.to_s, resource: resource) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is so action
can be a symbol, otherwise the auth just fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good, my only feedback would be to add longer names and maybe some comments to fetcher.rb
-- my guess is we'll be pointing a lot of people towards that file as a way to teach them the concepts
backends/rails/lib/fetcher.rb
Outdated
kinds = Hash.new { |k| raise "Unsupported constraint kind: #{k}" } | ||
kinds['Eq'] = kinds['In'] = ->(q, c) { q.where param[c] } | ||
kinds['Neq'] = ->(q, c) { q.where.not param[c] } | ||
it['Eq'] = it['In'] = ->(q, c) { q.where param[c] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feeling like this file might be sacrificing some readability for conciseness/performance. IMO the goal here is that someone can look at this file and use it to build their own fetchers, so it's probably worth lengthening variable names, adding some comments, etc.
I took a stab at restructuring it with some longer variable names and inlining the instance_variable_set
. What do you think?
module Fetcher
def self.included(base) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
base.class_eval do
to_activerecord_clause = lambda do |constraint|
if constraint.field.nil?
# When field is empty, we should match using ID
{ primary_key => constraint.value.send(primary_key) }
else
{ c.field => c.value }
end
end
@constraint_handlers = {
'Eq': ->(query, constraint) { query.where to_activerecord_clause[constraint] },
'In': ->(query, constraint) { query.where to_activerecord_clause[constraint] },
'Neq': ->(query, constraint) { query.where.not to_activerecord_clause[constraint] }
}
@constraint_handlers.default_proc = proc { |k| "Unsupported constraint kind: #{k}" }
@constraint_handlers.freeze
def self.build_query(constraints)
constraints.reduce(all) do |query, c|
@constraint_handlers[constraint.kind][query, constraint]
end
end
def self.exec_query(query)
query.distinct.to_a
end
def self.combine_query(one, two)
one.or(two)
end
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're totally right, I'll change this 👍
actor_has_role_for_resource(org: Org, _role: String, repo: Repo) if | ||
repo.org = org; | ||
actor_has_role_for_resource(_: User{repo_roles: roles}, name: String, repo: Repo) if | ||
role in roles and role matches { name: name, repo: repo }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
No description provided.