<p>Thanks to <strong>@RobinSchambach</strong> advices, I was able to find a safe solution to handle this permission problematic.</p>

<p>This is possible using two main addings:</p>

<ul>
<li>Register a <strong>new custom permission</strong> from the plugin

<ul>
<li><em>This prevents user from be able to access other users assets</em></li>
</ul></li>
<li>Add a <strong>custom User field</strong> on the assets to assign ownership ;

<ul>
<li><em>Using this we can verify that it was uploaded from user requesting the file deletion</em></li>
</ul></li>
</ul>

<p><strong>In the plugin Service:</strong></p>

<pre><code>public function linkUserToAssets($assets = [])
{
    $currentUser = Craft::$app-&gt;getUser()-&gt;getIdentity();
    if ($currentUser &amp;&amp; Craft::$app-&gt;request-&gt;getIsSiteRequest()
        &amp;&amp; Craft::$app-&gt;request-&gt;getIsPost()) {
        foreach ($assets-&gt;all() as $asset) {
            if (isset($asset-&gt;id) &amp;&amp; !empty($asset-&gt;id)) {
                $asset = Craft::$app-&gt;assets-&gt;getAssetById($asset-&gt;id);
                if (isset($asset-&gt;assetsOwner)) {
                    $asset-&gt;assetsOwner = [$currentUser-&gt;id];
                    Craft::$app-&gt;elements-&gt;saveElement($asset);
                }
            }
        }
    }
}
</code></pre>

<p>This adds a function to call before each entry is saved, to assign the user's ownership on entry's assets using the <code>assetsOwner</code> custom field.</p>

<p><strong>In the plugin Module:</strong></p>

<pre><code>Event::on(
    UserPermissions::class,
    UserPermissions::EVENT_REGISTER_PERMISSIONS,
    function(RegisterUserPermissionsEvent $event) {
        $event-&gt;permissions['User'] = [
            'deleteOwnAssets' =&gt; [
                'label' =&gt; 'Delete Own Assets'
            ],
        ];
    }
);
</code></pre>

<p>This adds a custom permission in the CP which should be added to group of users who will perform this action.</p>

<p><strong>In the plugin Controller:</strong></p>

<pre><code>public function actionDeleteAsset()
{
    $currentUser = Craft::$app-&gt;getUser()-&gt;getIdentity();
    if ($currentUser) {
        $request = Craft::$app-&gt;getRequest();
        $assetId = $request-&gt;getBodyParam('assetId');
        $asset = Craft::$app-&gt;getAssets()-&gt;getAssetById($assetId);

        if ($asset-&gt;assetsOwner[0]-&gt;id !== $currentUser-&gt;id || !Craft::$app-&gt;user-&gt;checkPermission('deleteOwnAssets')) {
            return $this-&gt;asErrorJson(Craft::t('app', self::TEXT_PERMISSION_REQUIRED));
        }
    }
}
</code></pre>

<p>This deletes requested assets if the current user was the owner of the asset (using <code>assetsOwner</code> custom field) and has the required custom permission (in this case, <code>deleteOwnAssets</code>).</p>

CC BY-SA 4.0
2018-09-25T10:28:28.953Z
You'll likely receive deprecation errors with that code and there are a few "mistakes"/useless calls. If you want we can talk in detail at Slack about it
Robin Schambach
CC BY-SA 4.0
2018-09-25T10:15:27.860Z
2018-09-25T10:15:27.860Z
Romain P.
<p>I have a front-end form where logged users can upload and delete their personal files.</p>

<p>These users have the strict minimum permissions required to interact with this form. They can only Create, Publish and Delete their own entries in the section where the form create these entries.</p>

<p>In order to be able to delete these files from Craft (and not from only the field they're linked in this entry), I have created this custom action in a module:</p>

<pre><code>&lt;?php

namespace modules\mymodule\controllers;

use Craft;
use craft\web\Controller;
use craft\elements\Asset;

class DefaultController extends Controller
{

    public function actionDeleteAsset()
    {
        $this-&gt;requireAcceptsJson();
        $this-&gt;requireLogin();

        $currentUser = Craft::$app-&gt;getUser()-&gt;getIdentity();
        if (!$currentUser) {
            return $this-&gt;asErrorJson(Craft::t('app', 'Only a logged in user can delete an asset.'));
        } else {
            $request = Craft::$app-&gt;getRequest();
            $assetId = $request-&gt;getParam('assetId', '');
            $asset = Craft::$app-&gt;getAssets()-&gt;getAssetById($assetId);

            if (!empty($asset)) {
                if (!Craft::$app-&gt;getUser()-&gt;checkPermission('deleteFilesAndFoldersInVolume:' . $asset-&gt;volumeId)) {
                    return $this-&gt;asErrorJson(Craft::t('app', 'You don\'t have permission to delete this asset.'));
                } else {
                    Craft::$app-&gt;getElements()-&gt;deleteElementById($asset-&gt;id, Asset::class);
                    return $this-&gt;asJson([
                        'success' =&gt; true
                    ]);
                }
            } else {
                return $this-&gt;asErrorJson(Craft::t('app', 'This asset does not exists or has already been deleted.'));
            }
        }
    }

}
</code></pre>

<p>The problem is that <code>Craft::$app-&gt;getUser()-&gt;checkPermission('deleteFilesAndFoldersInVolume:' . $asset-&gt;volumeId)</code>is not entirely appropriate:</p>

<ul>
<li>I need to add Volume permissions (View volume + Remove files and
folders) to these users to allow them to delete their assets from the
front-end form ;</li>
<li>By adding these permissions, they have access to
other users' assets, which is a security problem ;</li>
</ul>

<p>So how can I check if user has the permissions to delete only his own assets? In other words, this user can only interact with the assets he has uploaded.</p>

CC BY-SA 4.0
2018-09-08T21:54:13.417Z
Why don't you just include a custom permission in your plugin?
Robin Schambach
CC BY-SA 4.0
2018-09-10T07:50:53.687Z
I didn't know it was possible. But even with custom permissions, how would you handle that? It seems that there is no user information I can get from the Asset element. So it means that I would have to create one custom different permission per user, and attach it to the file when the user use the front-end form. This would be a lot ot custom permissions for a website that would handle thousands of users, no?
Romain P.
CC BY-SA 4.0
2018-09-10T08:09:42.530Z
Just include one single permission if a user is able to delete an asset or not and include a `users` field to the asset and relate it to all users that may delete it. If the user is not related to the asset -> he can't delete it
Robin Schambach
CC BY-SA 4.0
2018-09-11T10:46:13.377Z
Thank you, I will go in this way and integrate it asap. So I'm gonna add a hook on user registration / use of the front-end form to attach the custom permission (https://docs.craftcms.com/v2/plugins/hooks-reference.html#general-hooks), then I will populate a custom field on file upload. I'll update my question / answer later here.
Romain P.
CC BY-SA 4.0
2018-09-11T11:02:28.383Z
There are no hooks in Craft 3, only events but yes
Robin Schambach
CC BY-SA 4.0
2018-09-25T10:20:24.547Z
@RobinSchambach, I have now posted my answer thanks to your advices.
Romain P.
<plugin-development><assets><frontend-form><delete>
Plugin development: how can I check if user has the permissions to delete only his own assets?
# Plugin development: how can I check if user has the permissions to delete only his own assets?

(Asked by: username_0 on 2018-09-07)

I have a front-end form where logged users can upload and delete their personal files.
These users have the strict minimum permissions required to interact with this form. They can only Create, Publish and Delete their own entries in the section where the form create these entries.
In order to be able to delete these files from Craft (and not from only the field they're linked in this entry), I have created this custom action in a module:
requireAcceptsJson();
        $this->requireLogin();

        $currentUser = Craft::$app->getUser()->getIdentity();
        if (!$currentUser) {
            return $this->asErrorJson(Craft::t('app', 'Only a logged in user can delete an asset.'));
        } else {
            $request = Craft::$app->getRequest();
            $assetId = $request->getParam('assetId', '');
            $asset = Craft::$app->getAssets()->getAssetById($assetId);

            if (!empty($asset)) {
                if (!Craft::$app->getUser()->checkPermission('deleteFilesAndFoldersInVolume:' . $asset->volumeId)) {
                    return $this->asErrorJson(Craft::t('app', 'You don\'t have permission to delete this asset.'));
                } else {
                    Craft::$app->getElements()->deleteElementById($asset->id, Asset::class);
                    return $this->asJson([
                        'success' => true
                    ]);
                }
            } else {
                return $this->asErrorJson(Craft::t('app', 'This asset does not exists or has already been deleted.'));
            }
        }
    }

}

The problem is that Craft::$app->getUser()->checkPermission('deleteFilesAndFoldersInVolume:' . $asset->volumeId)is not entirely appropriate:

I need to add Volume permissions (View volume + Remove files and
folders) to these users to allow them to delete their assets from the
front-end form ;
By adding these permissions, they have access to
other users' assets, which is a security problem ;

So how can I check if user has the permissions to delete only his own assets? In other words, this user can only interact with the assets he has uploaded.

**Tags:** plugin-development, assets, frontend-form, delete
> **Comments:**
> **username_1**: Why don't you just include a custom permission in your plugin?  
> **username_0**: I didn't know it was possible. But even with custom permissions, how would you handle that? It seems that there is no user information I can get from the Asset element. So it means that I would have to create one custom different permission per user, and attach it to the file when the user use the front-end form. This would be a lot ot custom permissions for a website that would handle thousands of users, no?  
> **username_1**: Just include one single permission if a user is able to delete an asset or not and include a `users` field to the asset and relate it to all users that may delete it. If the user is not related to the asset -> he can't delete it  
> **username_0**: Thank you, I will go in this way and integrate it asap. So I'm gonna add a hook on user registration / use of the front-end form to attach the custom permission (https://docs.craftcms.com/v2/plugins/hooks-reference.html#general-hooks), then I will populate a custom field on file upload. I'll update my question / answer later here.  
> **username_1**: There are no hooks in Craft 3, only events but yes  
> **username_0**: @RobinSchambach, I have now posted my answer thanks to your advices.  

---

## 1 answers

### Answer by username_0 on 2018-09-25. Score: 1

Thanks to @RobinSchambach advices, I was able to find a safe solution to handle this permission problematic.
This is possible using two main addings:

Register a new custom permission from the plugin


This prevents user from be able to access other users assets

Add a custom User field on the assets to assign ownership ;


Using this we can verify that it was uploaded from user requesting the file deletion


In the plugin Service:
public function linkUserToAssets($assets = [])
{
    $currentUser = Craft::$app->getUser()->getIdentity();
    if ($currentUser && Craft::$app->request->getIsSiteRequest()
        && Craft::$app->request->getIsPost()) {
        foreach ($assets->all() as $asset) {
            if (isset($asset->id) && !empty($asset->id)) {
                $asset = Craft::$app->assets->getAssetById($asset->id);
                if (isset($asset->assetsOwner)) {
                    $asset->assetsOwner = [$currentUser->id];
                    Craft::$app->elements->saveElement($asset);
                }
            }
        }
    }
}

This adds a function to call before each entry is saved, to assign the user's ownership on entry's assets using the assetsOwner custom field.
In the plugin Module:
Event::on(
    UserPermissions::class,
    UserPermissions::EVENT_REGISTER_PERMISSIONS,
    function(RegisterUserPermissionsEvent $event) {
        $event->permissions['User'] = [
            'deleteOwnAssets' => [
                'label' => 'Delete Own Assets'
            ],
        ];
    }
);

This adds a custom permission in the CP which should be added to group of users who will perform this action.
In the plugin Controller:
public function actionDeleteAsset()
{
    $currentUser = Craft::$app->getUser()->getIdentity();
    if ($currentUser) {
        $request = Craft::$app->getRequest();
        $assetId = $request->getBodyParam('assetId');
        $asset = Craft::$app->getAssets()->getAssetById($assetId);

        if ($asset->assetsOwner[0]->id !== $currentUser->id || !Craft::$app->user->checkPermission('deleteOwnAssets')) {
            return $this->asErrorJson(Craft::t('app', self::TEXT_PERMISSION_REQUIRED));
        }
    }
}

This deletes requested assets if the current user was the owner of the asset (using assetsOwner custom field) and has the required custom permission (in this case, deleteOwnAssets).

> **Comments:**
> **username_1**: You'll likely receive deprecation errors with that code and there are a few "mistakes"/useless calls. If you want we can talk in detail at Slack about it  

---

