gobrightspot / nova-detached-actions

A Laravel Nova tool to allow for placing actions in the Nova toolbar detached from the checkbox selection mechanism.
MIT License
168 stars 50 forks source link

Unauthorized to perform this action #39

Closed Peterragheb closed 3 years ago

Peterragheb commented 3 years ago

Laravel: 7.26.0 Nova: 3.8.4

If I try to use an action on a resource that doesn't have any entries. I get an error "Sorry! You are not authorized to perform this action.". Knowing that If I upgraded nova to 3.10.0 this will be fixed because nova introduced standalone actions in that version. Which if I did I won't be needing this package but I can't upgrade my nova version. So I consider this as a bug. Please help thank you :)

0xfrej commented 3 years ago

That's because you're using older nova. This package actually requires nova 3.10.0 to work, not 3.0. If you can't upgrade, I will share workaround with you

Peterragheb commented 3 years ago

Thank you for your fast response. Please share it with me if possible

0xfrej commented 3 years ago

You can do It by implementing own handleRequest to override nova's default (as standalone actions are implemented from the version 3.10+) This is mine

    /**
     * Execute the action for the given request.
     *
     * @param  \Laravel\Nova\Http\Requests\ActionRequest  $request
     * @return mixed
     * @throws MissingActionHandlerException
     */
    public function handleRequest(ActionRequest $request)
    {
        $method = ActionMethod::determine($this, $request->targetModel());

        if (! method_exists($this, $method)) {
            throw MissingActionHandlerException::make($this, $method);
        }

        $wasExecuted = false;

        $fields = $request->resolveFields();

        if (! $this->standalone) {
            $results = $request->chunks(
                static::$chunkCount, function ($models) use ($fields, $request, $method, &$wasExecuted) {
                    $models = $models->filterForExecution($request);

                    if (count($models) > 0) {
                        $wasExecuted = true;

                        return Brightspot\Nova\Tools\DetachedActions\DispatchAction::forModels(
                            $request, $this, $method, $models, $fields
                        );
                    }
                }
            );
        }
        else {
            $wasExecuted = true;
            $results = Brightspot\Nova\Tools\DetachedActions\DispatchAction::forModels(
                $request, $this, $method, collect([]), $fields
            );
        }

        if (! $wasExecuted) {
            return static::danger(__('Sorry! You are not authorized to perform this action.'));
        }

        return $this->handleResult($fields, $results);
    }

Note: You have to use DispatchAction from this package as it has already overridden method for this purpose (yes by default there are like 2-3 checks for this thing same in nova for some reason). Or you can always make your own.

And then you will probably want to specify action to be runnable without models

public function withModels(): self
    {
        $this->standalone = false;
        return $this;
    }

The implementation uses standalone property that is already present. And then in resource just use withModels() and you should be good to go. Let me know if it's working.

Peterragheb commented 3 years ago

Thank you for your detailed solution. But unfortunately It didn't work. I'm using the action to download file, It shows that the action ran successfully but the file doesn't get downloaded. When I add withModels() to the action the file gets downloaded but we're back to square one.

0xfrej commented 3 years ago

Maybe you could try use xdebug to see where it's getting stuck. I don't have time right now to try and replicate your issue.

Peterragheb commented 3 years ago

I figured it out. I had to add the dispatchaction to an array for the results in case of standalone

 $results =[
                \Brightspot\Nova\Tools\DetachedActions\DispatchAction::forModels(
                    $request, $this, $method, collect([]), $fields
                )
            ];
Peterragheb commented 3 years ago

Thank you so much for your help