How do you delete assets from a frontend form? 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?
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-&gt;requireAjaxRequest();

        $fileId = craft()-&gt;request-&gt;getRequiredPost('fileId');
        $file = craft()-&gt;assets-&gt;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-&gt;getFolder()-&gt;name != craft()-&gt;userSession-&gt;getUser()-&gt;username)
        {
            throw new HttpException(403);
        }

        $response = craft()-&gt;assets-&gt;deleteFiles($fileIds);
        $this-&gt;returnJson($response-&gt;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-&gt;requireAcceptsJson();

        $assetId = Craft::$app-&gt;request-&gt;getRequiredBodyParam('fileId');
        $asset = Craft::$app-&gt;assets-&gt;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-&gt;getFolder()-&gt;name != Craft::$app-&gt;user-&gt;getIdentity()-&gt;username) {
            throw new ForbiddenHttpException('Not permitted to delete asset ' . $assetId);
        }

        $success = Craft::$app-&gt;elements-&gt;deleteElement($asset);
        return $this-&gt;asJson([
            'success' =&gt; $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.