Overriding Locks

Locks automatically expire out after the "edit" page has been closed for 2 minutes, so this isn't normally required, but you can give admin users a way to "steal" a lock from another user.

First, grant the "Override Record Lock" permission to the relevant admin/developer roles. This is shared between all models, though you could create custom permissions if needed.

For each model, create a "Force edit" route (using the post() method):

use Alberon\NexusRecordLocking\Enums\Permission as RecordLockingPermission;

Route::post('examples/{example}/force-edit', [ExampleController::class, 'forceEdit'])
    ->name('examples.force-edit')
    ->can(RecordLockingPermission::OverrideRecordLock);

Then create the action that steals the lock and then redirects to the regular edit page:

public function forceEdit(Example $example)
{
    $example->stealLock();

    return redirect(route('examples.edit', $example));
}

We will add a link on the "show" page. Check if the user has the OverrideRecordLock permission:

use Alberon\NexusRecordLocking\Enums\Permission as RecordLockingPermission;

class Example extends Controller
{
    // ...

    public function show(Example $example)
    {
        return inertia('Examples/PageIndex', [
            'example' => data($example, [
                // ...
                'can_lock',
                'lockedBy.name',
            ]),
            'userCan' => user_can([
                // ...
                RecordLockingPermission::OverrideRecordLock,
            ]),
        ]);
    }
}

And if they do, pass the route to the alert:

<template #alerts>
    <AlertRecordLocked
        v-if="!example.can_lock"
        :locked-by="example.lockedBy"
        :override-url="userCan.OverrideRecordLock && $route('examples.force-edit', example)"
    />
</template>

If there is no "show" page, we need an alternative way to display the "Override Lock" button. We will redirect to the "index" page instead, and pass through the relevant record information.

In the edit() method (and destroy(), etc.):

public function edit(Example $example)
{
    if (!$example->lockRecord()) {
        return redirect()->route('examples.index', $example)
            ->with('examples.record-locked', [
                'lockedBy' => data($example->lockedBy, ['name']),
                'overrideUrl' => Gate::allows(RecordLockingPermission::OverrideRecordLock) ? route('examples.force-edit', $example) : null,
            ]);
    }

    return inertia('Examples/PageEdit', [
        // ...
        'lockKey' => $example->lock_key,
    ]);
}

In the index() method, retrieve the value from the session:

public function index()
{
    // ...

    return inertia('Examples/PageIndex', [
        // ...
        'recordLocked' => session('examples.record-locked'),
    ]);
}

And in the PageIndex.vue page:

<script>
    import AlertRecordLocked from '@alberon/nexus-record-locking/vue/AlertRecordLocked';
    // ...

    export default {
        components: {
            AlertRecordLocked,
            // ...
        },
        props: {
            // ...
            recordLocked: { type: Object },
        },
    }
</script>

<template>
    <LayoutMain>

        <template #alerts>
            <AlertRecordLocked v-if="recordLocked" v-bind="recordLocked" />
        </template>

        ...

    </LayoutMain>
</template>