Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions PERMISSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ You can assign permissions to users in several ways:
4. Choose users and permission level (view/edit)
5. Optionally cascade permissions to child items

**General Access** (`private` / `inherit` / `anyone_can_view`) can only be changed by library admins. Owners and creators can still share items with specific users via User Permissions.

#### Via Code
```php
use Tapp\FilamentLibrary\Services\PermissionService;
Expand Down Expand Up @@ -59,23 +61,37 @@ if ($libraryItem->hasPermission($user, 'edit')) {

## Advanced Configuration

### Custom User Model Integration
### Library Admin Access

Library admin checks go through `FilamentLibraryPlugin::isLibraryAdmin()`. Configure them with a callback (recommended) or via config:

```php
// In your AppServiceProvider
use Tapp\FilamentLibrary\FilamentLibraryPlugin;

public function boot(): void
{
FilamentLibraryPlugin::setLibraryAdminCallback(function ($user): bool {
return $user->hasRole('admin') || $user->hasRole('library-admin');
});
}
```

Or in `config/filament-library.php`:

```php
'admin_role' => 'Admin',
'admin_callback' => null, // or a callable
```

If you want to use the `HasLibraryAccess` trait for additional functionality:
Add the `LibraryUser` trait to your User model for personal folders and favorites (it does not control admin authorization):

```php
// In your User model
use Tapp\FilamentLibrary\Traits\HasLibraryAccess;
use Tapp\FilamentLibrary\Traits\LibraryUser;

class User extends Authenticatable
{
use HasLibraryAccess;

// Override to add role-based logic
public function isLibraryAdmin(): bool
{
return $this->hasRole('admin') || $this->hasRole('library-admin');
}
use LibraryUser;
}
```

Expand Down Expand Up @@ -124,7 +140,7 @@ The library items table includes a toggleable "Permissions" column that shows:

- All permission checks go through Laravel's authorization system
- Policies ensure consistent permission enforcement
- Fallback implementations work even without the `HasLibraryAccess` trait
- Fallback implementations work even without the `LibraryUser` trait
- Creator permissions are always respected

## Troubleshooting
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,6 @@ public function boot()
}
```

**Note:** By default, users have an `isLibraryAdmin()` method that returns `false`. You can override this in your User model for custom logic.

## Events

The package dispatches events your application can listen for to extend behavior (for example, search indexing, webhooks after uploads, ...).
Expand Down
4 changes: 0 additions & 4 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ parameters:
message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:getInheritedGeneralAccessDisplay\\(\\)\\.$#"
path: src/Resources/Pages

-
message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:hasPermission\\(\\)\\.$#"
path: src/Resources/Pages

-
message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:getSecureUrl\\(\\)\\.$#"
path: src/Resources/Pages
Expand Down
6 changes: 4 additions & 2 deletions src/FilamentLibraryPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ public function getId(): string
/**
* Set a custom callback to determine if a user is a library admin.
*
* @param callable $callback Function that receives a user and returns bool
* Pass null to clear a previously registered callback.
*
* @param (callable(Authenticatable): bool)|null $callback
*/
public static function setLibraryAdminCallback(callable $callback): void
public static function setLibraryAdminCallback(?callable $callback): void
{
static::$libraryAdminCallback = $callback;
}
Expand Down
25 changes: 9 additions & 16 deletions src/Policies/LibraryItemPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tapp\FilamentLibrary\Policies;

use Illuminate\Foundation\Auth\User;
use Tapp\FilamentLibrary\FilamentLibraryPlugin;
use Tapp\FilamentLibrary\Models\LibraryItem;

class LibraryItemPolicy
Expand All @@ -12,8 +13,7 @@ class LibraryItemPolicy
*/
public function viewAny(User $user): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand All @@ -26,8 +26,7 @@ public function viewAny(User $user): bool
*/
public function view(User $user, LibraryItem $libraryItem): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand All @@ -50,8 +49,7 @@ public function create(User $user): bool
*/
public function update(User $user, LibraryItem $libraryItem): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand All @@ -64,8 +62,7 @@ public function update(User $user, LibraryItem $libraryItem): bool
*/
public function delete(User $user, LibraryItem $libraryItem): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand All @@ -87,8 +84,7 @@ public function deleteAny(User $user): bool
*/
public function forceDelete(User $user, LibraryItem $libraryItem): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand All @@ -110,8 +106,7 @@ public function forceDeleteAny(User $user): bool
*/
public function restore(User $user, LibraryItem $libraryItem): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand All @@ -133,8 +128,7 @@ public function restoreAny(User $user): bool
*/
public function replicate(User $user, LibraryItem $libraryItem): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand All @@ -155,8 +149,7 @@ public function reorder(User $user): bool
*/
public function managePermissions(User $user, LibraryItem $libraryItem): bool
{
// Check if user is library admin
if (method_exists($user, 'isLibraryAdmin') && $user->isLibraryAdmin()) {
if (FilamentLibraryPlugin::isLibraryAdmin($user)) {
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Resources/Pages/EditFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ public function form(Schema $schema): Schema
$record = $this->getRecord();
$inherited = $record->getInheritedGeneralAccessDisplay();

$baseText = 'Set the baseline access level for this file. User-level permissions can override this setting.';
$baseText = 'Only library admins can change general access (e.g. make an item visible to everyone). Share with specific users via User Permissions instead.';

if ($inherited) {
return $baseText . "\n\nCurrently inheriting: {$inherited}";
}

return $baseText;
})
->visible(fn () => $this->getRecord()->hasPermission(auth()->user(), 'share')),
->visible(fn () => FilamentLibraryPlugin::isLibraryAdmin(auth()->user())),

// Creator select field
$this->getCreatorSelectField(),
Expand Down
4 changes: 2 additions & 2 deletions src/Resources/Pages/EditFolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ public function form(Schema $schema): Schema
$record = $this->getRecord();
$inherited = $record->getInheritedGeneralAccessDisplay();

$baseText = 'Set the baseline access level for this folder. User-level permissions can override this setting.';
$baseText = 'Only library admins can change general access (e.g. make an item visible to everyone). Share with specific users via User Permissions instead.';

if ($inherited) {
return $baseText . "\n\nCurrently inheriting: {$inherited}";
}

return $baseText;
})
->visible(fn () => $this->getRecord()->hasPermission(auth()->user(), 'share')),
->visible(fn () => FilamentLibraryPlugin::isLibraryAdmin(auth()->user())),

// Creator select field
$this->getCreatorSelectField(),
Expand Down
5 changes: 5 additions & 0 deletions src/Resources/Pages/EditLibraryItemPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ protected function mutateFormDataBeforeSave(array $data): array
// Set the updated_by field
$data['updated_by'] = auth()->user()?->id;

// Only library admins may change general access (e.g. anyone_can_view).
if (! FilamentLibraryPlugin::isLibraryAdmin(auth()->user())) {
unset($data['general_access']);
}

return $data;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Resources/Pages/EditLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ public function form(Schema $schema): Schema
$record = $this->getRecord();
$inherited = $record->getInheritedGeneralAccessDisplay();

$baseText = 'Set the baseline access level for this link. User-level permissions can override this setting.';
$baseText = 'Only library admins can change general access (e.g. make an item visible to everyone). Share with specific users via User Permissions instead.';

if ($inherited) {
return $baseText . "\n\nCurrently inheriting: {$inherited}";
}

return $baseText;
})
->visible(fn () => $this->getRecord()->hasPermission(auth()->user(), 'share')),
->visible(fn () => FilamentLibraryPlugin::isLibraryAdmin(auth()->user())),

// Creator select field
$this->getCreatorSelectField(),
Expand Down
11 changes: 8 additions & 3 deletions src/Services/PermissionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,16 @@ public function bulkAssignPermissions($items, array $data): void
{
$userIds = $data['user_ids'] ?? [];
$permission = $data['permission'] ?? 'view';
$generalAccess = $data['general_access'] ?? 'private';
$canManageGeneralAccess = FilamentLibraryPlugin::isLibraryAdmin(auth()->user());
$generalAccess = $canManageGeneralAccess && array_key_exists('general_access', $data)
? $data['general_access']
: null;

foreach ($items as $item) {
// Update the general access level for the item
$item->update(['general_access' => $generalAccess]);
// Only library admins may change general access (e.g. anyone_can_view).
if ($generalAccess !== null) {
$item->update(['general_access' => $generalAccess]);
}

// Assign permissions to users
foreach ($userIds as $userId) {
Expand Down
4 changes: 3 additions & 1 deletion src/Support/UserAssignmentFilters.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ public static function filterFields(string $usersField = 'user_ids'): array
->map(function (Field $field) use ($usersField): Field {
return $field
->live()
->afterStateUpdated(fn (Get $get, Set $set): mixed => static::refreshSelectedUsersIfSelectingAll($get, $set, $usersField));
->afterStateUpdated(function (Get $get, Set $set) use ($usersField): void {
static::refreshSelectedUsersIfSelectingAll($get, $set, $usersField);
});
})
->all();
}
Expand Down
19 changes: 0 additions & 19 deletions src/Traits/LibraryUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,4 @@ public function favoriteLibraryItems(): BelongsToMany
return $this->belongsToMany(FilamentLibraryPlugin::libraryItemModelClass(), 'library_item_favorites')
->withTimestamps();
}

/**
* Check if the user is a library admin.
*
* Library admins can:
* - View all library items (including root items)
* - Edit any library item
* - Delete any library item
* - Manage permissions on any item
* - Access all library functionality
*
* Override this method to add role-based logic.
*/
public function isLibraryAdmin(): bool
{
// Default implementation - override this method to add role-based logic
// For example: return $this->hasRole('admin') || $this->hasRole('library-admin');
return false;
}
}
Loading
Loading