#4, #112: Default permissions can now be saved. There's a link to the default permissions screen from the admin/settings screen. The permissions cache rebuild now takes into account the default permissions. The permissions tab on the albums screen now correctly shows text based on if permissions are inherited from a parent album, or the default permissions.

This commit is contained in:
Andy Heathershaw 2018-09-23 22:20:03 +01:00
parent da0667711a
commit a5569924be
11 changed files with 346 additions and 62 deletions

View File

@ -123,6 +123,12 @@ class Album extends Model
} }
} }
if (is_null($current->parent_album_id) && $current->is_permissions_inherited)
{
// Use default permissions list
return 0;
}
return $current->id; return $current->id;
} }

View File

@ -0,0 +1,9 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class AlbumDefaultAnonymousPermission extends Model
{
}

View File

@ -3,6 +3,9 @@
namespace App\Helpers; namespace App\Helpers;
use App\Album; use App\Album;
use App\AlbumDefaultAnonymousPermission;
use App\AlbumDefaultGroupPermission;
use App\AlbumDefaultUserPermission;
use App\Permission; use App\Permission;
use App\User; use App\User;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@ -77,6 +80,10 @@ class PermissionsHelper
$albumGroupPermissions = DB::table('album_group_permissions')->get(); $albumGroupPermissions = DB::table('album_group_permissions')->get();
$albumAnonPermissions = DB::table('album_anonymous_permissions')->get(); $albumAnonPermissions = DB::table('album_anonymous_permissions')->get();
$defaultAlbumUserPermissions = AlbumDefaultUserPermission::all();
$defaultAlbumGroupPermissions = AlbumDefaultGroupPermission::all();
$defaultAnonPermissions = AlbumDefaultAnonymousPermission::all();
// Get a list of all user->group memberships // Get a list of all user->group memberships
$userGroups = DB::table('user_groups')->get(); $userGroups = DB::table('user_groups')->get();
@ -88,7 +95,55 @@ class PermissionsHelper
{ {
$effectiveAlbumID = $album->effectiveAlbumIDForPermissions(); $effectiveAlbumID = $album->effectiveAlbumIDForPermissions();
$anonymousPermissions = array_filter($albumAnonPermissions->toArray(), function($item) use ($effectiveAlbumID) if ($effectiveAlbumID === 0)
{
/* Use the default permissions list */
foreach ($defaultAnonPermissions as $anonymousPermission)
{
$permissionsCache[] = [
'album_id' => $album->id,
'permission_id' => $anonymousPermission->permission_id,
'created_at' => new \DateTime(),
'updated_at' => new \DateTime()
];
}
foreach ($defaultAlbumUserPermissions as $userPermission)
{
$permissionsCache[] = [
'user_id' => $userPermission->user_id,
'album_id' => $album->id,
'permission_id' => $userPermission->permission_id,
'created_at' => new \DateTime(),
'updated_at' => new \DateTime()
];
}
foreach ($defaultAlbumGroupPermissions as $groupPermission)
{
// Get a list of users in this group, and add one per user
$usersInGroup = array_filter($userGroups->toArray(), function ($item) use ($groupPermission)
{
return $item->group_id = $groupPermission->group_id;
});
foreach ($usersInGroup as $userGroup)
{
$permissionsCache[] = [
'user_id' => $userGroup->user_id,
'album_id' => $album->id,
'permission_id' => $groupPermission->permission_id,
'created_at' => new \DateTime(),
'updated_at' => new \DateTime()
];
}
}
}
else
{
/* Use the specified album-specific permissions */
$anonymousPermissions = array_filter($albumAnonPermissions->toArray(), function ($item) use ($effectiveAlbumID)
{ {
return ($item->album_id == $effectiveAlbumID); return ($item->album_id == $effectiveAlbumID);
}); });
@ -103,7 +158,7 @@ class PermissionsHelper
]; ];
} }
$userPermissions = array_filter($albumUserPermissions->toArray(), function($item) use ($effectiveAlbumID) $userPermissions = array_filter($albumUserPermissions->toArray(), function ($item) use ($effectiveAlbumID)
{ {
return ($item->album_id == $effectiveAlbumID); return ($item->album_id == $effectiveAlbumID);
}); });
@ -119,7 +174,7 @@ class PermissionsHelper
]; ];
} }
$groupPermissions = array_filter($albumGroupPermissions->toArray(), function($item) use ($effectiveAlbumID) $groupPermissions = array_filter($albumGroupPermissions->toArray(), function ($item) use ($effectiveAlbumID)
{ {
return ($item->album_id == $effectiveAlbumID); return ($item->album_id == $effectiveAlbumID);
}); });
@ -127,7 +182,7 @@ class PermissionsHelper
foreach ($groupPermissions as $groupPermission) foreach ($groupPermissions as $groupPermission)
{ {
// Get a list of users in this group, and add one per user // Get a list of users in this group, and add one per user
$usersInGroup = array_filter($userGroups->toArray(), function($item) use ($groupPermission) $usersInGroup = array_filter($userGroups->toArray(), function ($item) use ($groupPermission)
{ {
return $item->group_id = $groupPermission->group_id; return $item->group_id = $groupPermission->group_id;
}); });
@ -144,6 +199,7 @@ class PermissionsHelper
} }
} }
} }
}
$this->savePermissionsCache($permissionsCache); $this->savePermissionsCache($permissionsCache);
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use App\Album; use App\Album;
use App\AlbumDefaultAnonymousPermission;
use App\AlbumDefaultGroupPermission; use App\AlbumDefaultGroupPermission;
use App\AlbumDefaultUserPermission; use App\AlbumDefaultUserPermission;
use App\AlbumRedirect; use App\AlbumRedirect;
@ -30,6 +31,30 @@ use Illuminate\Support\Facades\View;
class AlbumController extends Controller class AlbumController extends Controller
{ {
public static function doesGroupHaveDefaultPermission(Group $group, Permission $permission)
{
return AlbumDefaultGroupPermission::where([
'group_id' => $group->id,
'permission_id' => $permission->id
])->count() > 0;
}
public static function doesUserHaveDefaultPermission($user, Permission $permission)
{
// User will be null for anonymous users
if (is_null($user))
{
return AlbumDefaultAnonymousPermission::where(['permission_id' => $permission->id])->count() > 0;
}
else
{
return AlbumDefaultUserPermission::where([
'user_id' => $user->id,
'permission_id' => $permission->id
])->count() > 0;
}
}
public function __construct() public function __construct()
{ {
$this->middleware('auth'); $this->middleware('auth');
@ -252,6 +277,130 @@ class AlbumController extends Controller
]); ]);
} }
public function setDefaultGroupPermissions(Request $request)
{
$this->authorizeAccessToAdminPanel('admin:manage-albums');
if ($request->get('action') == 'add_group' && $request->has('group_id'))
{
/* Add a new group to the default permission list */
/** @var Group $group */
$group = Group::where('id', $request->get('group_id'))->first();
if (is_null($group))
{
App::abort(404);
}
// Link all default permissions to the group
/** @var Permission $permission */
foreach (Permission::where(['section' => 'album', 'is_default' => true])->get() as $permission)
{
$defaultPermission = new AlbumDefaultGroupPermission();
$defaultPermission->group_id = $group->id;
$defaultPermission->permission_id = $permission->id;
$defaultPermission->save();
}
}
else if ($request->get('action') == 'update_group_permissions')
{
/* Update existing group permissions for this album */
AlbumDefaultGroupPermission::truncate();
$permissions = $request->get('permissions');
if (is_array($permissions))
{
foreach ($permissions as $groupID => $permissionIDs)
{
foreach ($permissionIDs as $permissionID)
{
$defaultPermission = new AlbumDefaultGroupPermission();
$defaultPermission->group_id = $groupID;
$defaultPermission->permission_id = $permissionID;
$defaultPermission->save();
}
}
}
}
// Rebuild the permissions cache
$helper = new PermissionsHelper();
$helper->rebuildCache();
return redirect(route('albums.defaultPermissions'));
}
public function setDefaultUserPermissions(Request $request)
{
$this->authorizeAccessToAdminPanel('admin:manage-albums');
if ($request->get('action') == 'add_user' && $request->has('user_id'))
{
/* Add a new user to the permission list for this album */
/** @var User $user */
$user = User::where('id', $request->get('user_id'))->first();
if (is_null($user))
{
App::abort(404);
}
// Link all default permissions to the group
/** @var Permission $permission */
foreach (Permission::where(['section' => 'album', 'is_default' => true])->get() as $permission)
{
$defaultPermission = new AlbumDefaultUserPermission();
$defaultPermission->user_id = $user->id;
$defaultPermission->permission_id = $permission->id;
$defaultPermission->save();
}
}
else if ($request->get('action') == 'update_user_permissions')
{
/* Update existing user and anonymous permissions for this album */
AlbumDefaultAnonymousPermission::truncate();
AlbumDefaultUserPermission::truncate();
$permissions = $request->get('permissions');
if (is_array($permissions))
{
if (isset($permissions['anonymous']))
{
foreach ($permissions['anonymous'] as $permissionID)
{
$defaultPermission = new AlbumDefaultAnonymousPermission();
$defaultPermission->permission_id = $permissionID;
$defaultPermission->save();
}
}
foreach ($permissions as $key => $value)
{
$userID = intval($key);
if ($userID == 0)
{
// Skip non-numeric IDs (e.g. anonymous)
continue;
}
foreach ($value as $permissionID)
{
$defaultPermission = new AlbumDefaultUserPermission();
$defaultPermission->user_id = $userID;
$defaultPermission->permission_id = $permissionID;
$defaultPermission->save();
}
}
}
}
// Rebuild the permissions cache
$helper = new PermissionsHelper();
$helper->rebuildCache();
return redirect(route('albums.defaultPermissions'));
}
public function setGroupPermissions(Request $request, $id) public function setGroupPermissions(Request $request, $id)
{ {
$this->authorizeAccessToAdminPanel('admin:manage-albums'); $this->authorizeAccessToAdminPanel('admin:manage-albums');

View File

@ -35,7 +35,9 @@ return [
'album_change_more_details' => 'You can change more details about this album by editing it. Click the button below to go to the album\'s Edit page.', 'album_change_more_details' => 'You can change more details about this album by editing it. Click the button below to go to the album\'s Edit page.',
'album_inheriting_permissions_p1' => 'Inherited permissions are in effect', 'album_inheriting_permissions_p1' => 'Inherited permissions are in effect',
'album_inheriting_permissions_p2' => 'This album is inheriting permissions from a parent album and therefore permissions cannot be applied directly to it.', 'album_inheriting_permissions_p2' => 'This album is inheriting permissions from a parent album and therefore permissions cannot be applied directly to it.',
'album_inheriting_permissions_p2_toplevel' => 'This album is inheriting permissions from the default album permissions and therefore permissions cannot be applied directly to it.',
'album_inheriting_permissions_p3' => 'You can change the permissions applied to this album (and other albums under the same parent) from the :l_parent_start parent album\'s permissions tab:l_parent_end, or stop permissions from being inherited by :l_edit_start editing this album:l_edit_end.', 'album_inheriting_permissions_p3' => 'You can change the permissions applied to this album (and other albums under the same parent) from the :l_parent_start parent album\'s permissions tab:l_parent_end, or stop permissions from being inherited by :l_edit_start editing this album:l_edit_end.',
'album_inheriting_permissions_p3_toplevel' => 'You can change the permissions applied to this album from the :l_defperms_start default album permissions screen:l_defperms_end, or stop permissions from being inherited by :l_edit_start editing this album:l_edit_end.',
'album_no_cameras_found_p1' => 'No cameras were found', 'album_no_cameras_found_p1' => 'No cameras were found',
'album_no_cameras_found_p2' => 'Upload more photos to this album or ensure the cameras you use support Exif image tagging.', 'album_no_cameras_found_p2' => 'Upload more photos to this album or ensure the cameras you use support Exif image tagging.',
'album_no_photos_p1' => 'No photos in this album', 'album_no_photos_p1' => 'No photos in this album',
@ -232,6 +234,8 @@ return [
'analytics_tab' => 'Analytics', 'analytics_tab' => 'Analytics',
'comments_moderation' => 'Moderation', 'comments_moderation' => 'Moderation',
'comments_tab' => 'Comments', 'comments_tab' => 'Comments',
'default_album_permissions' => 'Default Album Permissions',
'default_album_permissions_intro' => 'Configure a set of permissions to apply to top-level albums that do not have their own permissions, and as a base set of permissions for newly-created albums.',
'permissions_cache' => 'Permissions Cache', 'permissions_cache' => 'Permissions Cache',
'permissions_cache_intro' => 'Blue Twilight maintains the permissions each user has to albums in the database. If you feel these aren\'t correct based on what\'s configured, you can rebuild the cache by clicking the button below.', 'permissions_cache_intro' => 'Blue Twilight maintains the permissions each user has to albums in the database. If you feel these aren\'t correct based on what\'s configured, you can rebuild the cache by clicking the button below.',
'rebuild_permissions_cache' => 'Rebuild Permissions Cache', 'rebuild_permissions_cache' => 'Rebuild Permissions Cache',

View File

@ -28,7 +28,7 @@ return [
'email_label' => 'E-mail address:', 'email_label' => 'E-mail address:',
'email_placeholder' => 'name@example.com', 'email_placeholder' => 'name@example.com',
'enable_profile_page_label' => 'Allow others to see my profile page', 'enable_profile_page_label' => 'Allow others to see my profile page',
'inherit_album_permissions' => 'Inherit permissions from parent album', 'inherit_album_permissions' => 'Inherit permissions from parent album / default settings',
'labels_label' => 'Labels:', 'labels_label' => 'Labels:',
'login_action' => 'Login', 'login_action' => 'Login',
'name_label' => 'Name:', 'name_label' => 'Name:',

View File

@ -18,6 +18,9 @@
<p class="mb-0">@lang('admin.default_album_permissions.intro_2')</p> <p class="mb-0">@lang('admin.default_album_permissions.intro_2')</p>
</div> </div>
<hr/>
<h5 style="font-weight: bold;">@lang('admin.security_groups_heading')</h5>
<form action="{{ route('albums.set_default_group_permissions') }}" method="post"> <form action="{{ route('albums.set_default_group_permissions') }}" method="post">
{{ csrf_field() }} {{ csrf_field() }}
@ -28,7 +31,7 @@
'key_id' => 'group_' . $group->id, 'key_id' => 'group_' . $group->id,
'object_id' => $group->id, 'object_id' => $group->id,
'title' => $group->name, 'title' => $group->name,
'callback' => [$album, 'doesGroupHavePermission'], 'callback' => [\App\Http\Controllers\Admin\AlbumController::class, 'doesGroupHaveDefaultPermission'],
'callback_object' => $group, 'callback_object' => $group,
'parent_id' => 'groups-accordion' 'parent_id' => 'groups-accordion'
]) ])
@ -67,7 +70,7 @@
'key_id' => 'anonymous', 'key_id' => 'anonymous',
'object_id' => 'anonymous', 'object_id' => 'anonymous',
'title' => trans('admin.anonymous_users'), 'title' => trans('admin.anonymous_users'),
'callback' => [$album, 'doesUserHavePermission'], 'callback' => [\App\Http\Controllers\Admin\AlbumController::class, 'doesUserHaveDefaultPermission'],
'callback_object' => null, 'callback_object' => null,
'parent_id' => 'users-accordion' 'parent_id' => 'users-accordion'
]) ])
@ -77,7 +80,7 @@
'key_id' => 'user_' . $user->id, 'key_id' => 'user_' . $user->id,
'object_id' => $user->id, 'object_id' => $user->id,
'title' => $user->name, 'title' => $user->name,
'callback' => [$album, 'doesUserHavePermission'], 'callback' => [\App\Http\Controllers\Admin\AlbumController::class, 'doesUserHaveDefaultPermission'],
'callback_object' => $user, 'callback_object' => $user,
'parent_id' => 'users-accordion' 'parent_id' => 'users-accordion'
]) ])
@ -103,3 +106,36 @@
</div> </div>
</div> </div>
@endsection @endsection
@push('scripts')
<script type="text/javascript">
{{-- Select All/None links on the permissions tab --}}
$('a.select-all').click(function() {
$('input:checkbox', $(this).closest('.card-body')).prop('checked', true);
return false;
});
$('a.select-none').click(function() {
$('input:checkbox', $(this).closest('.card-body')).prop('checked', false);
return false;
});
{{-- Type-ahead support for users textbox on the permissions tab --}}
var userDataSource = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '{{ route('users.searchJson') }}?q=%QUERY',
wildcard: '%QUERY'
}
});
$('#user-search-textbox').typeahead(null, {
name: 'user-search',
display: 'name',
source: userDataSource
});
$('#user-search-textbox').bind('typeahead:select', function(ev, suggestion) {
$('#user-id-field').val(suggestion.id);
});
</script>
@endpush

View File

@ -54,7 +54,7 @@
</select> </select>
</div> </div>
<div class="form-group" v-if="!isParentAlbum"> <div class="form-group">
<div class="mt-3 form-check"> <div class="mt-3 form-check">
<input type="checkbox" class="form-check-input" id="inherit-permissions" name="is_permissions_inherited" v-model="is_inherit_permissions" /> <input type="checkbox" class="form-check-input" id="inherit-permissions" name="is_permissions_inherited" v-model="is_inherit_permissions" />
<label class="form-check-label" for="inherit-permissions"> <label class="form-check-label" for="inherit-permissions">

View File

@ -54,7 +54,7 @@
</select> </select>
</div> </div>
<div class="form-group" v-if="!isParentAlbum"> <div class="form-group">
<div class="mt-3 form-check"> <div class="mt-3 form-check">
<input type="checkbox" class="form-check-input" id="inherit-permissions" name="is_permissions_inherited"{{ $album->is_permissions_inherited ? ' checked="checked"' : '' }}> <input type="checkbox" class="form-check-input" id="inherit-permissions" name="is_permissions_inherited"{{ $album->is_permissions_inherited ? ' checked="checked"' : '' }}>
<label class="form-check-label" for="inherit-permissions"> <label class="form-check-label" for="inherit-permissions">

View File

@ -292,6 +292,14 @@
<hr/> <hr/>
<fieldset>
<legend>@lang('admin.settings.default_album_permissions')</legend>
<p>@lang('admin.settings.default_album_permissions_intro')</p>
<a href="{{ route('albums.defaultPermissions') }}" class="btn btn-primary">@lang('admin.settings.default_album_permissions')</a>
</fieldset>
<hr/>
<fieldset> <fieldset>
<legend>@lang('admin.settings.permissions_cache')</legend> <legend>@lang('admin.settings.permissions_cache')</legend>
<p>@lang('admin.settings.permissions_cache_intro')</p> <p>@lang('admin.settings.permissions_cache_intro')</p>

View File

@ -1,5 +1,9 @@
<div role="tabpanel" class="tab-pane{{ $active_tab == 'permissions' ? ' active' : '' }}" id="permissions-tab"> <div role="tabpanel" class="tab-pane{{ $active_tab == 'permissions' ? ' active' : '' }}" id="permissions-tab">
@if ($album->is_permissions_inherited) @if ($album->is_permissions_inherited)
@php
$effectiveAlbumID = $album->effectiveAlbumIDForPermissions()
@endphp
@if ($effectiveAlbumID > 0)
<div class="text-center mt-3"> <div class="text-center mt-3">
<h4 class="text-info"><b>@lang('admin.album_inheriting_permissions_p1')</b></h4> <h4 class="text-info"><b>@lang('admin.album_inheriting_permissions_p1')</b></h4>
<p>@lang('admin.album_inheriting_permissions_p2')</p> <p>@lang('admin.album_inheriting_permissions_p2')</p>
@ -10,6 +14,18 @@
'l_edit_end' => '</a>' 'l_edit_end' => '</a>'
])</p> ])</p>
</div> </div>
@else
<div class="text-center mt-3">
<h4 class="text-info"><b>@lang('admin.album_inheriting_permissions_p1')</b></h4>
<p>@lang('admin.album_inheriting_permissions_p2_toplevel')</p>
<p>@lang('admin.album_inheriting_permissions_p3_toplevel', [
'l_defperms_start' => sprintf('<a href="%s">', route('albums.defaultPermissions')),
'l_defperms_end' => '</a>',
'l_edit_start' => sprintf('<a href="%s">', route('albums.edit', [$album->id])),
'l_edit_end' => '</a>'
])</p>
</div>
@endif
@else @else
<h4>@lang('admin.security_heading')</h4> <h4>@lang('admin.security_heading')</h4>
<p>@lang('admin.security_text')</p> <p>@lang('admin.security_text')</p>