-
-
Notifications
You must be signed in to change notification settings - Fork 230
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
feature: add search_result_path and search? authorization method #1634
feature: add search_result_path and search? authorization method #1634
Conversation
Code Climate has analyzed commit 28d85ba and detected 0 issues on this pull request. View more on Code Climate. |
@@ -120,12 +121,18 @@ def apply_search_metadata(models, avo_resource) | |||
models.map do |model| | |||
resource = avo_resource.dup.hydrate(model: model).hydrate_fields(model: model) | |||
|
|||
if resource.search_result_url | |||
url = resource.search_result_url.call(model, main_app, params) |
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 had to pass main_app
to be able to use url helpers in the lambda.
I had to pass params
to be able to check if the search is global or not.
Is there a better way of doing that?
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.
If we use the Evaluation Host we will be able to delegate main_app
to the view_context
.
See 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've changed to use the search host, but I think we still need to pass model
since the evaluation host does not seem to have the resource model instance. What do you think?
|
||
write_in_search "São Paulo" | ||
expect(page).to have_content "São Paulo" | ||
# expect(page).to have_link(href: "/any/custom/#{city.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.
I couldn't get that commented assert passing, I've seen this url in the search response but for somehow I can't see it in the page html during test
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 might need to regex it from the page.
# expect(page).to have_link(href: "/any/custom/#{city.id}") | |
# expect(page).to have_link(href: /\/any/custom/#{city.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.
The regex doesn't work also.
During the test, if I print url
I can see /any/custom/1
, but not in page.body
, that's why the assert fail 🤔
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.
should I remove this commented line? Do you have any other suggestion on how to assert that?
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.
Thanks for working on this @glaucocustodio! This is a good feature indeed!
Regarding search_policy_class
; Instead of having another policy to work with that only has one method index?
, how about we use the policy of that resource (which you can customize using authorization_policy
) and add another method search?
(which once can customize it using different-policy-methods).
This would DRY up the code IMHO.
The search_result_url
is 👨🍳🤌 (chef's kiss). One thing I'd do is use an Evaluation host. That will allow us not to pass in variables to that block and for better future-proofing.
Let me know if I can help with that.
@@ -120,12 +121,18 @@ def apply_search_metadata(models, avo_resource) | |||
models.map do |model| | |||
resource = avo_resource.dup.hydrate(model: model).hydrate_fields(model: model) | |||
|
|||
if resource.search_result_url | |||
url = resource.search_result_url.call(model, main_app, params) |
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.
If we use the Evaluation Host we will be able to delegate main_app
to the view_context
.
See this.
|
||
write_in_search "São Paulo" | ||
expect(page).to have_content "São Paulo" | ||
# expect(page).to have_link(href: "/any/custom/#{city.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.
You might need to regex it from the page.
# expect(page).to have_link(href: "/any/custom/#{city.id}") | |
# expect(page).to have_link(href: /\/any/custom/#{city.id}/) |
Sorry, I didn't give you the full context, I have the following policies: class AdminPolicy < ApplicationPolicy
def index?
allowed?
end
def show?
allowed?
end
def create?
allowed?
end
def update?
allowed?
end
def destroy?
allowed?
end
def upload_attachments?
allowed?
end
def download_attachments?
allowed?
end
def delete_attachments?
allowed?
end
class Scope < Scope
def resolve
scope.all
end
end
private
def allowed?
user.admin?
end
end
# used by the Resource
class ReportPolicy < AdminPolicy
end
# used by the tool controller
module Customers
class ReportPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
end
end
I would rather managing customer policies in |
I understand your usage. I just think it would fall more in-line with what we currently have which is all things related to the authorization of a resource (CRUD, associations, attachments) are controlled from one policy. def search?
allowed?
end Otherwise, everyone will have to add a new policy for search with just one method So it would be something like class AdminPolicy < ApplicationPolicy
def index?
allowed?
end
def show?
allowed?
end
def create?
allowed?
end
...
def search?
allowed?
end
end Does that make sense? Regarding the evaluation host, apologies, I didn't provide an example for that. I'll push some code to show what I mean. |
Check out my latest commit with the self.search_result_path = -> do
# you have access to resource, record, view_context and more from ResourceRecordHost
avo.resources_city_path record, custom: "yup"
end |
How would Avo look for config.authorization_methods = {
index: 'search?',
} |
It would be just config.authorization_methods = {
search: 'search?',
} So instead of thinking of search as something like the |
But for that we need to replace |
Yes, correct. # fetch the configured name or use the default :search
action = Avo.configuration.authorization_methods.stringify_keys['search'] || :search
next unless @authorization.set_record(resource.model_class).authorize_action(action, raise_exception: false) |
We don't need this bit: config.authorization_methods = {
search: 'search?',
} It will work out of the box now, thanks for the suggestion 🙃 Please let me know if you wanna change something else. |
@glaucocustodio I'll have a look and merge it tomorrow. Today was swamped for me. |
No worries, hopefully the tests will pass next time |
Thank you for working on this @glaucocustodio! You championed this feature from 0 to 1! Good job! |
Thank you for guiding me to the best solution @adrianthedev, I am proud to contribute back to Avo 💙 |
Add two new class attributes to
Avo::BaseResource
to further customize the search behaviour:Context
An Avo app contains the following classes:
When a customer searches for a report on the global search, Avo 2.28 will use
ReportPolicy
to authorize the search and it will deny since a customer can't manage ReportResource.In order to fix that, I am introducing
search_policy_class
. This class attribute will allow people to set which policy class must be used to authorize seaches:Once the authorization is fixed with the
search_policy_class
above, another problem is found: Avo 2.28 will point to/avo/resources/reports/:report_id
as url in the search results. Remember: customers can't manage reports, so, search results should point to/avo/customers/reports/:report_id
instead, that's whysearch_result_url
has been introduced:In the example above, if the search is global (performed possibly by a customer), search results will point to
customer_report_path
, otherwise, if it's performed on the ReportResource index page (only by an admin) it will point to/avo/resources/reports/:report_id
(sames as in Avo 2.28).Checklist:
Manual review steps