10

I am creating a proof of concept for a client in Craft where the client's customers can manage projects from the frontend of a Craft install.

I have a frontend form working correctly for creating a new project and uploading files attached to it... however the missing piece to the puzzle for full management is being able to delete a project entry and also being able to manage the media attached to the project entry.

Is it possible to let a frontend user manage assets, in particular deleting assets from their username folder?

  • 1
    Hey Alan, I just removed your two additional questions, as they each warrant their own posts. – Brandon Kelly Aug 19 '14 at 20:55
  • 1
    Thanks @BrandonKelly so much for your thorough answer and the edits. I hope I am not spamming the SE site too much by breaking the other questions out into two new questions: How do you delete entries from a frontend form? and Is it possible to use the assets modal on the front end?. – Alan Miller Aug 20 '14 at 4:10
  • @AlanMiller Not spamming at all, glad you split these into separate questions! As individual questions, you'll be able to get better, more detailed responses. Plus, it's way more useful to any future visitors who may only share one of your questions. Splitting them up is definitely the right move! – Lindsey D Aug 20 '14 at 5:15
  • @brandon is their a way to delete an asset in this manner in Craft 3? – kinoli Jan 28 '19 at 6:23
  • @kinoli just updated my answer for Craft 3. – Brandon Kelly Jan 29 '19 at 11:44
9

You can create a POST request via Ajax to the assets/deleteFile (Craft 2) / assets/delete-asset (Craft 3) controller action:

Craft 2:

$('#delete-file').click(function() {
    var data = {
        fileId: 100
    };

    $.post('/actions/assets/deleteFile', data, function(response) {
        // ...
    });
});

Craft 3:

$('#delete-file').click(function() {
    var data = {
        assetId: 100
    };

    $.post('/actions/assets/delete-asset', data, function(response) {
        // ...
    });
});

That controller action will require that the user is logged-in with a user account that has the “Remove files” permission on the asset source that the file belongs to. Granting that permission to a user will give them the ability to delete any file within that asset source though - not just their own. So this is probably not a good idea.

A better way of doing this would be to write a module that provides its own controller that does its own permission checking and handles the file deletion. It would look something like this:

Craft 2:

class MyController extends BaseController
{
    public function actionDeleteFile()
    {
        $this->requireAjaxRequest();

        $fileId = craft()->request->getRequiredPost('fileId');
        $file = craft()->assets->getFileById($fileId);

        if (!$file)
        {
            throw new Exception('Could not find a file with the ID '.$fileId);
        }

        // Make sure that it's within a folder with the same name as the user's username
        if ($file->getFolder()->name != craft()->userSession->getUser()->username)
        {
            throw new HttpException(403);
        }

        $response = craft()->assets->deleteFiles($fileIds);
        $this->returnJson($response->getResponseData());
    }
}

Craft 3:

use Craft;
use craft\web\Controller;
use yii\web\BadRequestHttpException;
use yii\web\ForbiddenHttpException;
use yii\web\Response;

class MyController extends Controller
{
    public function actionDeleteFile(): Response
    {
        $this->requireAcceptsJson();

        $assetId = Craft::$app->request->getRequiredBodyParam('fileId');
        $asset = Craft::$app->assets->getAssetById($assetId);

        if (!$asset) {
            throw new BadRequestHttpException('Invalid asset ID: ' . $assetId);
        }

        // Make sure that it's within a folder with the same name as the user's username
        if ($asset->getFolder()->name != Craft::$app->user->getIdentity()->username) {
            throw new ForbiddenHttpException('Not permitted to delete asset ' . $assetId);
        }

        $success = Craft::$app->elements->deleteElement($asset);
        return $this->asJson([
            'success' => $success,
        ]);
    }
}

With that in place, you’d just need to update your JavaScript to point to your deleteFile/delete-file action instead of Craft’s.

  • So, how do I get the fileId to pass into the controller? I have tried {{entry.myFileHandle.id}} and a bunch of other stuff that is not working for me. – David A McInnis Sep 18 '14 at 22:27
  • 1
    @DavidAaronMcInnis entry.myAssetsFieldHandle.first().id would be one way. – Brandon Kelly Sep 18 '14 at 22:28
  • Does the above post via Ajax method for deleting a file in Craft 3 still work? Been trying it but just getting error: Bad request yii\web\BadRequestHttpException: Unable to verify your data submission – mmc501 Dec 4 '19 at 16:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.