Skip to content
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] Custom access closures #5335

Merged
merged 7 commits into from
Oct 15, 2023
Merged

[Feature] Custom access closures #5335

merged 7 commits into from
Oct 15, 2023

Conversation

tabacitu
Copy link
Member

@tabacitu tabacitu commented Oct 3, 2023

WHY

BEFORE - What was wrong? What was happening before this PR?

We could not prevent access to an entire operation. ✅
But could NOT prevent access to an operation for a certain entry. ❌

For example, in a Product CRUD, say a user

  • had access to list and show all items;
  • BUT only had access to update and delete THEIR items;

Before this PR, that was very difficult to do in Backpack. You had to override the Update operation and the Update button. 🤢Horrible.

AFTER - What is happening after this PR?

An access condition can still be true and false like before. But in addition to that, it can also be a callable.

The developer can define their own closure that defines if an operation has access or not. And inside that closure, they have access to $entry, so they can define access depending on $entry, backpack_user() etc.

That means you can do THIS in your ProductCrudController:

public function setup()
    {
        // ...

        CRUD::setAccessCondition(['update', 'delete'], function ($entry) {
            if (backpack_user()->isSuperAdmin()) {
                return true;
            }

            if ($entry->user->id == backpack_user()->id) {
                return true;
            }

            return false;
        });
    }

Note that this is one of those VERY FEW things that is best done in the setup() method, so that it applies for all operations. For example, you want to set this access closure for the update and delete operations even during the list operation, so that the update and delete buttons get hidden... like magic 🪄

HOW

How did you achieve that, in technical terms?

  • added a few methods:
    • hasAccessCondition(string $operation) : bool
    • getAccessCondition(string $operation) : bool|callable|null
    • setAccessCondition(array|string $operation, bool|callable|null $condition) : void
  • added a second OPTIONAL parameter to the check functions:
    • hasAccess($operation, $entry)
    • hasAccessOrFail($operation, $entry)
    • hasAccessToAll($operation, $entry)
    • hasAccessToAny($operation, $entry)
    • this second parameter is optional - if missing, Backpack will pass the current entry to the closure (if available);

Is it a breaking change?

NO. All extra parameters are optional. All return types and parameters types I've added are exactly as the ones in the comment blocks before. No change in scope for old functionality.

How can we test the before & after?

Use the example above in a CrudController. You should notice:

  • the update and delete buttons disappear for the entries you exclude
  • the show button still shows
  • if you manually go to the update page, it will throw a 403 error

@tabacitu
Copy link
Member Author

tabacitu commented Oct 3, 2023

PRO companion for this PR: https://github.com/Laravel-Backpack/PRO/pull/208

@promatik
Copy link
Contributor

How come we didn't have this feature until now 😶
It's amazing!

image

Co-authored-by: António Almeida <[email protected]>
@tabacitu
Copy link
Member Author

Awesome! Added docs for it here - Laravel-Backpack/docs#516 - please check and merge both.

@promatik when this is merged and tagged, please let me know, so I'll write a quick article about it on our blog.

@promatik promatik merged commit 4fca689 into main Oct 15, 2023
3 checks passed
@promatik promatik deleted the callable-access branch October 15, 2023 23:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants