#3: Permissions can now be set on what users can do with photos in an album. This required re-thinking the available permissions slightly. Photo owners can do anything.

This commit is contained in:
Andy Heathershaw 2017-04-16 09:00:57 +01:00
parent 1312808d75
commit 2d8ba9da16
18 changed files with 556 additions and 348 deletions

View File

@ -36,7 +36,7 @@ class AlbumController extends Controller
{ {
$this->authorizeAccessToAdminPanel('admin:manage-albums'); $this->authorizeAccessToAdminPanel('admin:manage-albums');
$album = $this->loadAlbum($id); $album = $this->loadAlbum($id, 'upload-photos');
$photos = $album->photos() $photos = $album->photos()
->where('is_analysed', false) ->where('is_analysed', false)
->orderBy('created_at') ->orderBy('created_at')
@ -83,7 +83,7 @@ class AlbumController extends Controller
{ {
$this->authorizeAccessToAdminPanel('admin:manage-albums'); $this->authorizeAccessToAdminPanel('admin:manage-albums');
$album = $this->loadAlbum($id); $album = $this->loadAlbum($id, 'delete');
return Theme::render('admin.delete_album', ['album' => $album]); return Theme::render('admin.delete_album', ['album' => $album]);
} }
@ -98,7 +98,7 @@ class AlbumController extends Controller
{ {
$this->authorizeAccessToAdminPanel('admin:manage-albums'); $this->authorizeAccessToAdminPanel('admin:manage-albums');
$album = $this->loadAlbum($id); $album = $this->loadAlbum($id, 'delete');
// Delete all the photo files // Delete all the photo files
/** @var Photo $photo */ /** @var Photo $photo */
@ -122,12 +122,17 @@ class AlbumController extends Controller
* @param int $id * @param int $id
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function edit($id) public function edit(Request $request, $id)
{ {
$this->authorizeAccessToAdminPanel('admin:manage-albums'); $this->authorizeAccessToAdminPanel('admin:manage-albums');
$album = $this->loadAlbum($id); $album = $this->loadAlbum($id);
if (!$request->session()->has('_old_input'))
{
$request->session()->flash('_old_input', $album->toArray());
}
return Theme::render('admin.edit_album', ['album' => $album]); return Theme::render('admin.edit_album', ['album' => $album]);
} }
@ -153,7 +158,7 @@ class AlbumController extends Controller
$this->authorizeAccessToAdminPanel('admin:manage-albums'); $this->authorizeAccessToAdminPanel('admin:manage-albums');
/** @var Album $album */ /** @var Album $album */
$album = $this->loadAlbum($id); $album = $this->loadAlbum($id, 'change-permissions');
if ($request->get('action') == 'add_group' && $request->has('group_id')) if ($request->get('action') == 'add_group' && $request->has('group_id'))
{ {
@ -209,7 +214,7 @@ class AlbumController extends Controller
$this->authorizeAccessToAdminPanel('admin:manage-albums'); $this->authorizeAccessToAdminPanel('admin:manage-albums');
/** @var Album $album */ /** @var Album $album */
$album = $this->loadAlbum($id); $album = $this->loadAlbum($id, 'change-permissions');
if ($request->get('action') == 'add_user' && $request->has('user_id')) if ($request->get('action') == 'add_user' && $request->has('user_id'))
{ {
@ -331,6 +336,11 @@ class AlbumController extends Controller
$activeTab = $request->get('tab'); $activeTab = $request->get('tab');
if (!$request->session()->has('_old_input'))
{
$request->session()->flash('_old_input', $album->toArray());
}
return Theme::render('admin.show_album', [ return Theme::render('admin.show_album', [
'active_tab' => (strlen($activeTab) == 0) ? 'photos' : $activeTab, 'active_tab' => (strlen($activeTab) == 0) ? 'photos' : $activeTab,
'album' => $album, 'album' => $album,
@ -428,11 +438,8 @@ class AlbumController extends Controller
App::abort(404); App::abort(404);
return null; return null;
} }
else if (!Auth::user()->can($permission, $album))
{ $this->authorize($permission, $album);
App::abort(403);
return null;
}
return $album; return $album;
} }

View File

@ -95,13 +95,7 @@ class PhotoController extends Controller
{ {
$this->authorizeAccessToAdminPanel(); $this->authorizeAccessToAdminPanel();
/** @var Photo $photo */ $photo = $this->loadPhoto($id, 'delete');
$photo = Photo::where('id', intval($id))->first();
if (is_null($photo))
{
App::abort(404);
return null;
}
$photoService = new PhotoService($photo); $photoService = new PhotoService($photo);
$photoService->delete(); $photoService->delete();
@ -116,12 +110,7 @@ class PhotoController extends Controller
settype($horizontal, 'boolean'); settype($horizontal, 'boolean');
settype($vertical, 'boolean'); settype($vertical, 'boolean');
$photo = Photo::where('id', intval($photoId))->first(); $photo = $this->loadPhoto($photoId, 'manipulate');
if (is_null($photo))
{
App::abort(404);
return null;
}
$photoService = new PhotoService($photo); $photoService = new PhotoService($photo);
$photoService->flip($horizontal, $vertical); $photoService->flip($horizontal, $vertical);
@ -131,11 +120,7 @@ class PhotoController extends Controller
{ {
$this->authorizeAccessToAdminPanel(); $this->authorizeAccessToAdminPanel();
$photo = Photo::where('id', intval($photoId))->first(); $photo = $this->loadPhoto($photoId, 'manipulate');
if (is_null($photo))
{
App::abort(404);
}
$newAlbum = Album::where('id', intval($request->get('new_album_id')))->first(); $newAlbum = Album::where('id', intval($request->get('new_album_id')))->first();
if (is_null($newAlbum)) if (is_null($newAlbum))
@ -162,13 +147,7 @@ class PhotoController extends Controller
{ {
$this->authorizeAccessToAdminPanel(); $this->authorizeAccessToAdminPanel();
/** @var Photo $photo */ $photo = $this->loadPhoto($photoId, 'change-metadata');
$photo = Photo::where('id', intval($photoId))->first();
if (is_null($photo))
{
App::abort(404);
return null;
}
$result = ['is_successful' => false, 'message' => '']; $result = ['is_successful' => false, 'message' => ''];
@ -192,12 +171,7 @@ class PhotoController extends Controller
{ {
$this->authorizeAccessToAdminPanel(); $this->authorizeAccessToAdminPanel();
$photo = Photo::where('id', intval($photoId))->first(); $photo = $this->loadPhoto($photoId, 'manipulate');
if (is_null($photo))
{
App::abort(404);
return null;
}
if ($angle != 90 && $angle != 180 && $angle != 270) if ($angle != 90 && $angle != 180 && $angle != 270)
{ {
@ -222,7 +196,7 @@ class PhotoController extends Controller
$photoFiles = $request->files->get('photo'); $photoFiles = $request->files->get('photo');
// Load the linked album // Load the linked album
$album = $this->loadAlbum($request->get('album_id')); $album = $this->loadAlbum($request->get('album_id'), 'upload-photos');
$isSuccessful = false; $isSuccessful = false;
// Create the folder to hold the analysis results if not already present // Create the folder to hold the analysis results if not already present
@ -406,16 +380,9 @@ class PhotoController extends Controller
{ {
$this->authorizeAccessToAdminPanel(); $this->authorizeAccessToAdminPanel();
/** @var Album $album */ $album = $this->loadAlbum($albumId);
$album = Album::where('id', intval($albumId))->first();
if (is_null($album)) if ($request->has('bulk-apply'))
{
App::abort(404);
return null;
}
if ($request->has('bulk-action'))
{ {
$numberChanged = $this->applyBulkActions($request, $album); $numberChanged = $this->applyBulkActions($request, $album);
} }
@ -468,54 +435,87 @@ class PhotoController extends Controller
foreach ($photosToProcess as $photo) foreach ($photosToProcess as $photo)
{ {
$changed = false;
$photoService = new PhotoService($photo); $photoService = new PhotoService($photo);
$doNotSave = false; $doNotSave = false;
switch (strtolower($action)) switch (strtolower($action))
{ {
case 'change_album': case 'change_album':
$newAlbumId = intval($request->get('new-album-id')); if (Auth::user()->can('change-metadata', $photo))
if ($newAlbumId == $photo->album_id)
{ {
// Photo already belongs to this album, don't move $newAlbumId = intval($request->get('new-album-id'));
continue; if ($newAlbumId == $photo->album_id)
} {
// Photo already belongs to this album, don't move
continue;
}
$newAlbum = Album::where('id', $newAlbumId)->first(); $newAlbum = Album::where('id', $newAlbumId)->first();
if (is_null($newAlbum)) if (is_null($newAlbum))
{ {
App::abort(404); App::abort(404);
} }
$photoService->changeAlbum($newAlbum); $photoService->changeAlbum($newAlbum);
$changed = true;
}
break; break;
case 'delete': case 'delete':
$photoService->delete(); if (Auth::user()->can('delete', $photo))
$doNotSave = true; {
$photoService->delete();
$doNotSave = true;
$changed = true;
}
break; break;
case 'flip_both': case 'flip_both':
$photoService->flip(true, true); if (Auth::user()->can('manipulate', $photo))
{
$photoService->flip(true, true);
$changed = true;
}
break; break;
case 'flip_horizontal': case 'flip_horizontal':
$photoService->flip(true, false); if (Auth::user()->can('manipulate', $photo))
{
$photoService->flip(true, false);
$changed = true;
}
break; break;
case 'flip_vertical': case 'flip_vertical':
$photoService->flip(false, true); if (Auth::user()->can('manipulate', $photo))
{
$photoService->flip(false, true);
$changed = true;
}
break; break;
case 'refresh_thumbnails': case 'refresh_thumbnails':
$photoService->regenerateThumbnails(); if (Auth::user()->can('change-metadata', $photo))
{
$photoService->regenerateThumbnails();
$changed = true;
}
break; break;
case 'rotate_left': case 'rotate_left':
$photoService->rotate(90); if (Auth::user()->can('manipulate', $photo))
{
$photoService->rotate(90);
$changed = true;
}
break; break;
case 'rotate_right': case 'rotate_right':
$photoService->rotate(270); if (Auth::user()->can('manipulate', $photo))
{
$photoService->rotate(270);
$changed = true;
}
break; break;
} }
@ -524,7 +524,10 @@ class PhotoController extends Controller
$photo->save(); $photo->save();
} }
$numberChanged++; if ($changed)
{
$numberChanged++;
}
} }
return $numberChanged; return $numberChanged;
@ -534,7 +537,7 @@ class PhotoController extends Controller
* @param $id * @param $id
* @return Album * @return Album
*/ */
private function loadAlbum($id) private function loadAlbum($id, $permission = 'edit')
{ {
$album = Album::where('id', intval($id))->first(); $album = Album::where('id', intval($id))->first();
if (is_null($album)) if (is_null($album))
@ -543,9 +546,33 @@ class PhotoController extends Controller
return null; return null;
} }
$this->authorize($permission, $album);
return $album; return $album;
} }
/**
* @param $id
* @param string|null $permission
* @return Photo
*/
private function loadPhoto($id, $permission = null)
{
$photo = Photo::where('id', intval($id))->first();
if (is_null($photo))
{
App::abort(404);
return null;
}
if (!is_null($permission))
{
$this->authorize($permission, $photo);
}
return $photo;
}
private function updatePhotoDetails(Request $request, Album $album) private function updatePhotoDetails(Request $request, Album $album)
{ {
$numberChanged = 0; $numberChanged = 0;
@ -555,14 +582,13 @@ class PhotoController extends Controller
{ {
/** @var Photo $photo */ /** @var Photo $photo */
$photo = $album->photos()->where('id', intval($photoId))->first(); $photo = $album->photos()->where('id', intval($photoId))->first();
if (is_null($photo)) if (is_null($photo) || !Auth::user()->can('change-metadata', $photo))
{ {
continue; continue;
} }
$photo->fill($value); $photo->fill($value);
$photo->save(); $photo->save();
$numberChanged++; $numberChanged++;
} }

View File

@ -31,6 +31,46 @@ class AlbumPolicy
} }
} }
public function changePermissions(User $user, Album $album)
{
// Only the album's owner (or an admin, matched by the before() rule) can change permissions
return $user->id == $album->user_id;
}
public function changePhotoMetadata(User $user, Album $album)
{
if ($user->id == $album->user_id)
{
// The album's owner and can do everything
return true;
}
// Get the edit permission
$permission = Permission::where([
'section' => 'album',
'description' => 'change-photo-metadata'
])->first();
return $this->userHasPermission($user, $album, $permission);
}
public function deletePhotos(User $user, Album $album)
{
if ($user->id == $album->user_id)
{
// The album's owner and can do everything
return true;
}
// Get the edit permission
$permission = Permission::where([
'section' => 'album',
'description' => 'delete-photos'
])->first();
return $this->userHasPermission($user, $album, $permission);
}
public function edit(User $user, Album $album) public function edit(User $user, Album $album)
{ {
if ($user->id == $album->user_id) if ($user->id == $album->user_id)
@ -48,6 +88,40 @@ class AlbumPolicy
return $this->userHasPermission($user, $album, $permission); return $this->userHasPermission($user, $album, $permission);
} }
public function manipulatePhotos(User $user, Album $album)
{
if ($user->id == $album->user_id)
{
// The album's owner and can do everything
return true;
}
// Get the edit permission
$permission = Permission::where([
'section' => 'album',
'description' => 'manipulate-photos'
])->first();
return $this->userHasPermission($user, $album, $permission);
}
public function uploadPhotos(User $user, Album $album)
{
if ($user->id == $album->user_id)
{
// The album's owner and can do everything
return true;
}
// Get the edit permission
$permission = Permission::where([
'section' => 'album',
'description' => 'upload-photos'
])->first();
return $this->userHasPermission($user, $album, $permission);
}
public function view(User $user, Album $album) public function view(User $user, Album $album)
{ {
if ($user->id == $album->user_id) if ($user->id == $album->user_id)

View File

@ -0,0 +1,64 @@
<?php
namespace App\Policies;
use App\Photo;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class PhotoPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* @return void
*/
public function __construct()
{
//
}
public function before($user, $ability)
{
if ($user->is_admin)
{
// Admins can do anything
return true;
}
}
public function changeMetadata(User $user, Photo $photo)
{
if ($user->id == $photo->user_id)
{
// The photo's owner can do everything
return true;
}
return $user->can('change-photo-metadata', $photo->album);
}
public function delete(User $user, Photo $photo)
{
if ($user->id == $photo->user_id)
{
// The photo's owner can do everything
return true;
}
return $user->can('delete-photos', $photo->album);
}
public function manipulate(User $user, Photo $photo)
{
if ($user->id == $photo->user_id)
{
// The photo's owner can do everything
return true;
}
return $user->can('manipulate-photos', $photo->album);
}
}

View File

@ -8,6 +8,7 @@ use App\Group;
use App\Permission; use App\Permission;
use App\Photo; use App\Photo;
use App\Policies\AlbumPolicy; use App\Policies\AlbumPolicy;
use App\Policies\PhotoPolicy;
use App\User; use App\User;
use function GuzzleHttp\Psr7\mimetype_from_extension; use function GuzzleHttp\Psr7\mimetype_from_extension;
use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Gate;
@ -26,7 +27,8 @@ class AuthServiceProvider extends ServiceProvider
* @var array * @var array
*/ */
protected $policies = [ protected $policies = [
Album::class => AlbumPolicy::class Album::class => AlbumPolicy::class,
Photo::class => PhotoPolicy::class
]; ];
/** /**

View File

@ -111,7 +111,7 @@ class PermissionsSeeder extends Seeder
// album:edit-own-photos = controls if existing photos, owned by the current user, in the album can be edited // album:edit-own-photos = controls if existing photos, owned by the current user, in the album can be edited
DatabaseSeeder::createOrUpdate('permissions', [ DatabaseSeeder::createOrUpdate('permissions', [
'section' => 'album', 'section' => 'album',
'description' => 'edit-own-photos', 'description' => 'manipulate-photos',
'is_default' => true, 'is_default' => true,
'sort_order' => 40 'sort_order' => 40
]); ]);
@ -119,7 +119,7 @@ class PermissionsSeeder extends Seeder
// album:edit-other-photos = controls if existing photos, owned by other users, in the album can be edited // album:edit-other-photos = controls if existing photos, owned by other users, in the album can be edited
DatabaseSeeder::createOrUpdate('permissions', [ DatabaseSeeder::createOrUpdate('permissions', [
'section' => 'album', 'section' => 'album',
'description' => 'edit-other-photos', 'description' => 'change-photo-metadata',
'is_default' => true, 'is_default' => true,
'sort_order' => 50 'sort_order' => 50
]); ]);
@ -127,17 +127,9 @@ class PermissionsSeeder extends Seeder
// album:delete-own-photos = controls if existing photos, owned by the current user, in the album can be deleted // album:delete-own-photos = controls if existing photos, owned by the current user, in the album can be deleted
DatabaseSeeder::createOrUpdate('permissions', [ DatabaseSeeder::createOrUpdate('permissions', [
'section' => 'album', 'section' => 'album',
'description' => 'delete-own-photos', 'description' => 'delete-photos',
'is_default' => true, 'is_default' => true,
'sort_order' => 60 'sort_order' => 60
]); ]);
// album:delete-other-photos = controls if existing photos, owned by other users, in the album can be deleted
DatabaseSeeder::createOrUpdate('permissions', [
'section' => 'album',
'description' => 'delete-other-photos',
'is_default' => true,
'sort_order' => 70
]);
} }
} }

View File

@ -163,6 +163,7 @@ function EditPhotosViewModel(album_id, language, urls) {
return true; return true;
} }
var self = this;
var bulk_form = $(e.target).closest('form'); var bulk_form = $(e.target).closest('form');
if (this.bulkModifyMethod === 'change_album') { if (this.bulkModifyMethod === 'change_album') {
@ -176,6 +177,7 @@ function EditPhotosViewModel(album_id, language, urls) {
_bt_showLoadingModal(); _bt_showLoadingModal();
}); });
e.preventDefault();
return false; return false;
} }
else if (this.bulkModifyMethod === 'delete') { else if (this.bulkModifyMethod === 'delete') {
@ -194,12 +196,13 @@ function EditPhotosViewModel(album_id, language, urls) {
callback: function () { callback: function () {
self.isSubmitting = true; self.isSubmitting = true;
$('button[name="bulk-apply"]', bulk_form).click(); $('button[name="bulk-apply"]', bulk_form).click();
//_bt_showLoadingModal(); _bt_showLoadingModal();
} }
} }
} }
}); });
e.preventDefault();
return false; return false;
} }

View File

@ -11,6 +11,8 @@ return [
'album_no_photos_p1' => 'No photos in this album', 'album_no_photos_p1' => 'No photos in this album',
'album_no_photos_p2' => 'Click the "Upload photos" button below to get started.', 'album_no_photos_p2' => 'Click the "Upload photos" button below to get started.',
'album_no_photos_button' => 'Upload photos', 'album_no_photos_button' => 'Upload photos',
'album_permissions_album' => 'Album Permissions',
'album_permissions_photo' => 'Photo Permissions',
'album_photos_tab' => 'Photos', 'album_photos_tab' => 'Photos',
'album_saved_successfully' => 'The ":name" album was updated successfully.', 'album_saved_successfully' => 'The ":name" album was updated successfully.',
'album_security_tab' => 'Permissions', 'album_security_tab' => 'Permissions',

View File

@ -9,13 +9,12 @@ return [
'manage-users' => 'Manage users' 'manage-users' => 'Manage users'
], ],
'album' => [ 'album' => [
'change-photo-metadata' => 'Change metadata of photos in this album',
'delete' => 'Delete this album', 'delete' => 'Delete this album',
'delete-other-photos' => 'Delete photos owned by other users', 'delete-photos' => 'Delete photos from this album',
'delete-own-photos' => 'Delete user\'s own photos',
'edit' => 'Manage this album', 'edit' => 'Manage this album',
'edit-other-photos' => 'Edit photos owned by other users',
'edit-own-photos' => 'Edit user\'s own photos',
'list' => 'See this album in listings', 'list' => 'See this album in listings',
'manipulate-photos' => 'Manipulate photos in this album',
'upload-photos' => 'Upload photos into this album', 'upload-photos' => 'Upload photos into this album',
'view' => 'Access this album' 'view' => 'Access this album'
] ]

View File

@ -2,50 +2,53 @@
@section('title', 'Gallery Admin') @section('title', 'Gallery Admin')
@section('breadcrumb') @section('breadcrumb')
<div class="breadcrumb"> <li class="breadcrumb-item"><a href="{{ route('home') }}"><i class="fa fa-fw fa-home"></i></a></li>
<div class="container"> <li class="breadcrumb-item"><a href="{{ route('admin') }}">@lang('navigation.breadcrumb.admin')</a></li>
<ol class="breadcrumb"> <li class="breadcrumb-item"><a href="{{ route('albums.index') }}">@lang('navigation.breadcrumb.albums')</a></li>
<li><a href="{{ route('home') }}"><i class="fa fa-fw fa-home"></i></a></li> <li class="breadcrumb-item"><a href="{{ route('albums.show', ['id' => $album->id]) }}">{{ $album->name }}</a></li>
<li><a href="{{ route('admin') }}">@lang('navigation.breadcrumb.admin')</a></li> <li class="breadcrumb-item active">@lang('navigation.breadcrumb.edit_album')</li>
<li><a href="{{ route('albums.index') }}">@lang('navigation.breadcrumb.albums')</a></li>
<li><a href="{{ route('albums.show', ['id' => $album->id]) }}">{{ $album->name }}</a></li>
<li class="active">@lang('navigation.breadcrumb.edit_album')</li>
</ol>
</div>
</div>
@endsection @endsection
@section('content') @section('content')
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col">
<h1>@lang('admin.edit_album', ['album_name' => $album->name])</h1> <h1>@lang('admin.edit_album', ['album_name' => $album->name])</h1>
<p>@lang('admin.edit_album_intro')</p> <p>@lang('admin.edit_album_intro')</p>
<p>@lang('admin.edit_album_intro2', ['album_name' => $album->name])</p> <p>@lang('admin.edit_album_intro2', ['album_name' => $album->name])</p>
<hr/> <hr/>
{!! Form::model($album, ['route' => ['albums.update', $album->id], 'method' => 'PUT']) !!} <form method="post" action="{{ route('albums.update', [$album->id]) }}">
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}"> {{ csrf_field() }}
{!! Form::label('name', trans('forms.name_label'), ['class' => 'control-label']) !!} {{ method_field('PUT') }}
{!! Form::text('name', old('name'), ['class' => 'form-control']) !!}
@if ($errors->has('name')) <div class="form-group{{ $errors->has('name') ? ' has-danger' : '' }}">
<span class="help-block"> <label for="album-name" class="control-label">@lang('forms.name_label')</label>
<strong>{{ $errors->first('name') }}</strong> <input type="text" id="album-name" class="form-control" name="name" value="{{ old('name') }}" />
</span>
@endif
</div>
<div class="form-group"> @if ($errors->has('name'))
{!! Form::label('description', trans('forms.description_label'), ['class' => 'control-label']) !!} <div class="form-control-feedback">
{!! Form::textarea('description', old('description'), ['class' => 'form-control']) !!} <strong>{{ $errors->first('name') }}</strong>
</div> </div>
@endif
</div>
<div class="form-actions"> <div class="form-group{{ $errors->has('description') ? ' has-danger' : '' }}">
<a href="{{ route('albums.show', ['id' => $album->id]) }}" class="btn btn-default">@lang('forms.cancel_action')</a> <label for="album-description" class="control-label" name="name">@lang('forms.description_label')</label>
<button type="submit" class="btn btn-success"><i class="fa fa-fw fa-check"></i> @lang('forms.save_action')</button> <textarea class="form-control" id="album-description" rows="5" name="description">{{ old('description') }}</textarea>
</div>
{!! Form::close() !!} @if ($errors->has('description'))
<div class="form-control-feedback">
<strong>{{ $errors->first('description') }}</strong>
</div>
@endif
</div>
<div class="text-right">
<a href="{{ route('albums.show', ['id' => $album->id]) }}" class="btn btn-link">@lang('forms.cancel_action')</a>
<button type="submit" class="btn btn-success"><i class="fa fa-fw fa-check"></i> @lang('forms.save_action')</button>
</div>
</form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -42,9 +42,14 @@
<p style="margin-bottom: 0;"><b>{{ $album->photos_count }}</b> {{ trans_choice('admin.stats_widget.photos', $album->photos_count) }}</p> <p style="margin-bottom: 0;"><b>{{ $album->photos_count }}</b> {{ trans_choice('admin.stats_widget.photos', $album->photos_count) }}</p>
</td> </td>
<td class="text-right"> <td class="text-right">
@can('delete', $album) <div class="btn-group">
<a href="{{ route('albums.delete', ['id' => $album->id]) }}" class="btn btn-danger">@lang('forms.delete_action')</a> @can('edit', $album)
@endcan <a href="{{ route('albums.edit', ['id' => $album->id]) }}" class="btn btn-secondary">@lang('forms.edit_action')</a>
@endcan
@can('delete', $album)
<a href="{{ route('albums.delete', ['id' => $album->id]) }}" class="btn btn-danger">@lang('forms.delete_action')</a>
@endcan
</div>
</td> </td>
</tr> </tr>
@endforeach @endforeach

View File

@ -21,177 +21,28 @@
<div> <div>
<ul class="nav nav-tabs" role="tablist"> <ul class="nav nav-tabs" role="tablist">
@include(Theme::viewName('partials.tab'), ['tab_name' => 'photos', 'tab_icon' => 'photo', 'tab_text' => trans('admin.album_photos_tab')]) @include(Theme::viewName('partials.tab'), ['tab_name' => 'photos', 'tab_icon' => 'photo', 'tab_text' => trans('admin.album_photos_tab')])
@include(Theme::viewName('partials.tab'), ['tab_name' => 'upload', 'tab_icon' => 'upload', 'tab_text' => trans('admin.album_upload_tab')]) @can('upload-photos', $album)
@include(Theme::viewName('partials.tab'), ['tab_name' => 'permissions', 'tab_icon' => 'lock', 'tab_text' => trans('admin.album_security_tab')]) @include(Theme::viewName('partials.tab'), ['tab_name' => 'upload', 'tab_icon' => 'upload', 'tab_text' => trans('admin.album_upload_tab')])
@endcan
@can('change-permissions', $album)
@include(Theme::viewName('partials.tab'), ['tab_name' => 'permissions', 'tab_icon' => 'lock', 'tab_text' => trans('admin.album_security_tab')])
@endcan
@include(Theme::viewName('partials.tab'), ['tab_name' => 'settings', 'tab_icon' => 'cog', 'tab_text' => trans('admin.album_settings_tab')]) @include(Theme::viewName('partials.tab'), ['tab_name' => 'settings', 'tab_icon' => 'cog', 'tab_text' => trans('admin.album_settings_tab')])
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
{{-- Photos --}} {{-- Photos --}}
@include(Theme::viewName('partials.album_photos_tab')) @include(Theme::viewName('partials.album_photos_tab'))
@can('upload-photos', $album)
{{-- Upload --}} {{-- Upload --}}
@include(Theme::viewName('partials.album_upload_tab')) @include(Theme::viewName('partials.album_upload_tab'))
@endcan
{{-- Permissions --}} @can('change-permissions', $album)
<div role="tabpanel" class="tab-pane{{ $active_tab == 'permissions' ? ' active' : '' }}" id="permissions-tab"> {{-- Permissions --}}
<h4>@lang('admin.security_heading')</h4> @include(Theme::viewName('partials.album_permissions_tab'))
<p>@lang('admin.security_text')</p> @endcan
<hr/>
<h5 style="font-weight: bold;">@lang('admin.security_groups_heading')</h5>
<form action="{{ route('albums.set_group_permissions', ['id' => $album->id]) }}" method="post">
{{ csrf_field() }}
@if (count($existing_groups) > 0)
<div id="groups-accordion" role="tablist" aria-multiselectable="true">
@foreach ($existing_groups as $group)
@include(Theme::viewName('partials.album_permissions'), [
'key_id' => 'group_' . $group->id,
'object_id' => $group->id,
'title' => $group->name,
'callback' => [$album, 'doesGroupHavePermission'],
'callback_object' => $group,
'parent_id' => 'groups-accordion'
])
@endforeach
</div>
@endif
<div class="row mt-3">
<div class="col-md-4">
<select class="form-control" name="group_id" style="margin-bottom: 2px;"@if (count($add_new_groups) == 0) disabled="disabled"@endif>
@foreach ($add_new_groups as $group)
<option value="{{ $group->id }}">{{ $group->name }}</option>
@endforeach
</select>
</div>
<div class="col-md-2">
<button type="submit" name="action" value="add_group" class="btn btn-primary">Assign Permissions</button>
</div>
<div class="col-md-6 text-right">
<button type="submit" name="action" value="update_group_permissions" class="btn btn-success">
<i class="fa fa-fw fa-check"></i> @lang('forms.save_action')
</button>
</div>
</div>
</form>
<hr/>
<h5 style="font-weight: bold;">@lang('admin.security_users_heading')</h5>
<form action="{{ route('albums.set_user_permissions', ['id' => $album->id]) }}" method="post">
{{ csrf_field() }}
<div id="users-accordion" role="tablist" aria-multiselectable="true">
{{-- Anonymous users --}}
@include(Theme::viewName('partials.album_permissions'), [
'key_id' => 'anonymous',
'object_id' => 'anonymous',
'title' => trans('admin.anonymous_users'),
'callback' => [$album, 'doesUserHavePermission'],
'callback_object' => null,
'parent_id' => 'users-accordion'
])
@foreach ($existing_users as $user)
@include(Theme::viewName('partials.album_permissions'), [
'key_id' => 'user_' . $user->id,
'object_id' => $user->id,
'title' => $user->name,
'callback' => [$album, 'doesUserHavePermission'],
'callback_object' => $user,
'parent_id' => 'users-accordion'
])
@endforeach
</div>
<div class="row mt-3">
<div class="col-md-4">
<input class="form-control" name="user_name" id="user-search-textbox" size="20" style="margin-bottom: 2px;" />
<input type="hidden" name="user_id" id="user-id-field" />
</div>
<div class="col-md-2">
<button type="submit" name="action" value="add_user" class="btn btn-primary">Assign Permissions</button>
</div>
<div class="col-md-6 text-right">
<button type="submit" name="action" value="update_user_permissions" class="btn btn-success">
<i class="fa fa-fw fa-check"></i> @lang('forms.save_action')
</button>
</div>
</div>
</form>
</div>
{{-- Settings --}} {{-- Settings --}}
<div role="tabpanel" class="tab-pane{{ $active_tab == 'settings' ? ' active' : '' }}" id="settings-tab"> @include(Theme::viewName('partials.album_settings_tab'))
<form action="{{ route('albums.update', [$album->id]) }}" method="POST">
{{ csrf_field() }}
{{ method_field('PUT') }}
<h4><i class="fa fa-fw fa-info"></i> @lang('admin.album_basic_info_heading')</h4>
<p>@lang('admin.album_basic_info_intro')</p>
<div class="form-group{{ $errors->has('name') ? ' has-danger' : '' }}" style="margin-top: 20px;">
<label class="form-control-label" for="album-name">@lang('forms.name_label')</label>
<input type="text" class="form-control" id="album-name" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<div class="form-control-feedback">
<strong>{{ $errors->first('name') }}</strong>
</div>
@endif
</div>
<div class="form-group">
<label class="form-control-label" for="album-description">@lang('forms.description_label')</label>
<textarea class="form-control" id="album-description" name="description">{{ old('description') }}</textarea>
</div>
<hr/>
<h4><i class="fa fa-fw fa-paint-brush"></i> @lang('admin.album_appearance_heading')</h4>
<p>@lang('admin.album_appearance_intro')</p>
<div class="form-group" style="margin-top: 20px;">
<label class="control-label" for="album-view">@lang('forms.default_album_view_label')</label>
<select class="form-control" name="default_view">
@foreach ($allowed_views as $view)
<option value="{{ $view }}"{{ $view == old('default_view') ? ' selected="selected"' : '' }}>{{ $view }}</option>
@endforeach
</select>
</div>
<hr/>
<div class="row">
<div class="col-sm-6 push-sm-6">
<div class="card">
<div class="card-header">@lang('admin.save_changes_heading')</div>
<div class="card-block">
<p>@lang('admin.save_changes_intro')</p>
<div class="text-right">
<button type="submit" class="btn btn-success"><i class="fa fa-fw fa-floppy-o"></i> @lang('forms.save_action')</button>
</div>
</div>
</div>
</div>
<div class="col-sm-6 pull-sm-6">
<div class="card card-outline-danger">
<div class="card-header card-danger">@lang('admin.danger_zone_heading')</div>
<div class="card-block">
<p class="text-danger">@lang('admin.danger_zone_intro')</p>
<div>
<a href="{{ route('albums.delete', ['id' => $album->id]) }}" class="btn btn-danger">@lang('forms.delete_action')</a>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -9,20 +9,29 @@
<p style="margin-bottom: 20px;"><a class="select-all" href="#">Select All</a> &middot; <a class="select-none" href="">Select None</a></p> <p style="margin-bottom: 20px;"><a class="select-all" href="#">Select All</a> &middot; <a class="select-none" href="">Select None</a></p>
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4 mb-3">
<h5>Album Permissions</h5> <h5>@lang('admin.album_permissions_album')</h5>
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'list')]) @include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'list')])
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'view')]) @include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'view')])
@if ($object_id != 'anonymous')
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'edit')])
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'delete')])
@endif
</div> </div>
</div>
@foreach ($all_permissions as $permission) @if ($object_id != 'anonymous')
@if ($object_id == 'anonymous' && $permission->section == 'album' && $permission->description != 'list' && $permission->description != 'view') <div class="col-md-4 mb-3">
@continue <h5>@lang('admin.album_permissions_photo')</h5>
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'upload-photos')])
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'manipulate-photos')])
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'change-photo-metadata')])
@include(Theme::viewName('partials.permission_checkbox'), ['permission' => Theme::getPermission($all_permissions, 'album', 'delete-photos')])
</div>
@endif @endif
</div>
@endforeach
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,89 @@
<div role="tabpanel" class="tab-pane{{ $active_tab == 'permissions' ? ' active' : '' }}" id="permissions-tab">
<h4>@lang('admin.security_heading')</h4>
<p>@lang('admin.security_text')</p>
<hr/>
<h5 style="font-weight: bold;">@lang('admin.security_groups_heading')</h5>
<form action="{{ route('albums.set_group_permissions', ['id' => $album->id]) }}" method="post">
{{ csrf_field() }}
@if (count($existing_groups) > 0)
<div id="groups-accordion" role="tablist" aria-multiselectable="true">
@foreach ($existing_groups as $group)
@include(Theme::viewName('partials.album_permissions'), [
'key_id' => 'group_' . $group->id,
'object_id' => $group->id,
'title' => $group->name,
'callback' => [$album, 'doesGroupHavePermission'],
'callback_object' => $group,
'parent_id' => 'groups-accordion'
])
@endforeach
</div>
@endif
<div class="row mt-3">
<div class="col-md-4">
<select class="form-control" name="group_id" style="margin-bottom: 2px;"@if (count($add_new_groups) == 0) disabled="disabled"@endif>
@foreach ($add_new_groups as $group)
<option value="{{ $group->id }}">{{ $group->name }}</option>
@endforeach
</select>
</div>
<div class="col-md-2">
<button type="submit" name="action" value="add_group" class="btn btn-primary">Assign Permissions</button>
</div>
<div class="col-md-6 text-right">
<button type="submit" name="action" value="update_group_permissions" class="btn btn-success">
<i class="fa fa-fw fa-check"></i> @lang('forms.save_action')
</button>
</div>
</div>
</form>
<hr/>
<h5 style="font-weight: bold;">@lang('admin.security_users_heading')</h5>
<form action="{{ route('albums.set_user_permissions', ['id' => $album->id]) }}" method="post">
{{ csrf_field() }}
<div id="users-accordion" role="tablist" aria-multiselectable="true">
{{-- Anonymous users --}}
@include(Theme::viewName('partials.album_permissions'), [
'key_id' => 'anonymous',
'object_id' => 'anonymous',
'title' => trans('admin.anonymous_users'),
'callback' => [$album, 'doesUserHavePermission'],
'callback_object' => null,
'parent_id' => 'users-accordion'
])
@foreach ($existing_users as $user)
@include(Theme::viewName('partials.album_permissions'), [
'key_id' => 'user_' . $user->id,
'object_id' => $user->id,
'title' => $user->name,
'callback' => [$album, 'doesUserHavePermission'],
'callback_object' => $user,
'parent_id' => 'users-accordion'
])
@endforeach
</div>
<div class="row mt-3">
<div class="col-md-4">
<input class="form-control" name="user_name" id="user-search-textbox" size="20" style="margin-bottom: 2px;" />
<input type="hidden" name="user_id" id="user-id-field" />
</div>
<div class="col-md-2">
<button type="submit" name="action" value="add_user" class="btn btn-primary">Assign Permissions</button>
</div>
<div class="col-md-6 text-right">
<button type="submit" name="action" value="update_user_permissions" class="btn btn-success">
<i class="fa fa-fw fa-check"></i> @lang('forms.save_action')
</button>
</div>
</div>
</form>
</div>

View File

@ -14,29 +14,31 @@
@include (Theme::viewName('partials.single_photo_admin')) @include (Theme::viewName('partials.single_photo_admin'))
@endforeach @endforeach
<div class="pull-left" style="margin-bottom: 15px;"> <div class="row">
<p style="margin-bottom: 15px;"> <div class="col-md-6 mb-3">
<button v-on:click="selectAll" type="button" class="btn btn-secondary">@lang('admin.select_all_action')</button> <p style="margin-bottom: 15px;">
<button v-on:click="selectNone" type="button" class="btn btn-secondary">@lang('admin.select_none_action')</button> <button v-on:click="selectAll" type="button" class="btn btn-secondary">@lang('admin.select_all_action')</button>
</p> <button v-on:click="selectNone" type="button" class="btn btn-secondary">@lang('admin.select_none_action')</button>
<input v-model="selectAllInAlbum" type="hidden" name="select-all-album"/> </p>
<input v-model="selectAllInAlbum" type="hidden" name="select-all-album"/>
<div v-if="selectAllInAlbum" class="alert alert-warning"> <div v-if="selectAllInAlbum" class="alert alert-warning">
@lang('admin.select_all_album_active') @lang('admin.select_all_album_active')
</div>
<p><label class="control-label" for="bulk-action">@lang('forms.bulk_edit_photos_label')</label></p>
<input type="hidden" name="new-album-id" value="{{ $album->id }}"/>
<select name="bulk-action" v-model="bulkModifyMethod">
<option>@lang('forms.bulk_edit_photos_placeholder')</option>
@foreach ($bulk_actions as $key => $value)
<option value="{{ $key }}"{{ $key == old('bulk-action') ? ' selected="selected"' : '' }}>{{ $value }}</option>
@endforeach
</select>
<button type="submit" class="btn btn-sm btn-primary" name="bulk-apply" value="clicked" v-on:click="bulkModifySelected">@lang('forms.apply_action')</button>
</div>
<div class="col-md-6 text-right">
<button type="submit" class="btn btn-success">@lang('forms.save_action')</button>
</div> </div>
<p><label class="control-label" for="bulk-action">@lang('forms.bulk_edit_photos_label')</label></p>
<input type="hidden" name="new-album-id" value="{{ $album->id }}"/>
<select name="bulk-action" data-bind="value: bulkModifyMethod, enable: photoIDs().length > 0">
<option>@lang('forms.bulk_edit_photos_placeholder')</option>
@foreach ($bulk_actions as $key => $value)
<option value="{{ $key }}"{{ $key == old('bulk-action') ? ' selected="selected"' : '' }}>{{ $value }}</option>
@endforeach
</select>
<button type="submit" class="btn btn-sm btn-primary" name="bulk-apply" value="clicked" data-bind="click: bulkModifySelected, enable: photoIDs().length > 0">@lang('forms.apply_action')</button>
</div>
<div class="text-right">
<button type="submit" class="btn btn-success">@lang('forms.save_action')</button>
</div> </div>
</form> </form>

View File

@ -0,0 +1,69 @@
<div role="tabpanel" class="tab-pane{{ $active_tab == 'settings' ? ' active' : '' }}" id="settings-tab">
<form action="{{ route('albums.update', [$album->id]) }}" method="POST">
{{ csrf_field() }}
{{ method_field('PUT') }}
<h4><i class="fa fa-fw fa-info"></i> @lang('admin.album_basic_info_heading')</h4>
<p>@lang('admin.album_basic_info_intro')</p>
<div class="form-group{{ $errors->has('name') ? ' has-danger' : '' }}" style="margin-top: 20px;">
<label class="form-control-label" for="album-name">@lang('forms.name_label')</label>
<input type="text" class="form-control" id="album-name" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<div class="form-control-feedback">
<strong>{{ $errors->first('name') }}</strong>
</div>
@endif
</div>
<div class="form-group">
<label class="form-control-label" for="album-description">@lang('forms.description_label')</label>
<textarea class="form-control" id="album-description" name="description" rows="5">{{ old('description') }}</textarea>
</div>
<hr/>
<h4><i class="fa fa-fw fa-paint-brush"></i> @lang('admin.album_appearance_heading')</h4>
<p>@lang('admin.album_appearance_intro')</p>
<div class="form-group" style="margin-top: 20px;">
<label class="control-label" for="album-view">@lang('forms.default_album_view_label')</label>
<select class="form-control" name="default_view">
@foreach ($allowed_views as $view)
<option value="{{ $view }}"{{ $view == old('default_view') ? ' selected="selected"' : '' }}>{{ $view }}</option>
@endforeach
</select>
</div>
<hr/>
<div class="row">
<div class="col-md-6 push-md-6 mb-3">
<div class="card">
<div class="card-header">@lang('admin.save_changes_heading')</div>
<div class="card-block">
<p>@lang('admin.save_changes_intro')</p>
<div class="text-right">
<button type="submit" class="btn btn-success"><i class="fa fa-fw fa-floppy-o"></i> @lang('forms.save_action')</button>
</div>
</div>
</div>
</div>
@can('delete', $album)
<div class="col-md-6 pull-md-6 mb-3">
<div class="card card-outline-danger">
<div class="card-header card-danger">@lang('admin.danger_zone_heading')</div>
<div class="card-block">
<p class="text-danger">@lang('admin.danger_zone_intro')</p>
<div>
<a href="{{ route('albums.delete', ['id' => $album->id]) }}" class="btn btn-danger">@lang('forms.delete_action')</a>
</div>
</div>
</div>
</div>
@endcan
</div>
</form>
</div>

View File

@ -40,7 +40,7 @@
{{ Auth::user()->name }} {{ Auth::user()->name }}
{{--<img class="avatar" src="{{ Theme::gravatarUrl(Auth::user()->email, 42) }}" alt="{{ Auth::user()->name }}" title="{{ Auth::user()->name }}" />--}} {{--<img class="avatar" src="{{ Theme::gravatarUrl(Auth::user()->email, 42) }}" alt="{{ Auth::user()->name }}" title="{{ Auth::user()->name }}" />--}}
</a> </a>
<div class="dropdown-menu"> <div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="{{ route('auth.changePassword') }}">@lang('navigation.navbar.change_password')</a> <a class="dropdown-item" href="{{ route('auth.changePassword') }}">@lang('navigation.navbar.change_password')</a>
<a class="dropdown-item" href="{{ url('/logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">@lang('navigation.navbar.logout')</a> <a class="dropdown-item" href="{{ url('/logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">@lang('navigation.navbar.logout')</a>
<form id="logout-form" action="{{ url('/logout') }}" method="POST" style="display: none;"> <form id="logout-form" action="{{ url('/logout') }}" method="POST" style="display: none;">

View File

@ -9,44 +9,55 @@
</a><br/> </a><br/>
{{-- Photo editing tasks - these are hooked up using Javascript in admin/show_album --}} {{-- Photo editing tasks - these are hooked up using Javascript in admin/show_album --}}
<div class="text-center mt-1"> @php($canChangeMetadata = Auth::user()->can('change-metadata', $photo))
<div class="btn-group btn-group-sm" role="group"> @php($canManipulate = Auth::user()->can('manipulate', $photo))
@php($canDelete = Auth::user()->can('delete', $photo))
@if ($canManipulate || $canChangeMetadata || $canDelete)
<div class="text-center mt-1">
<div class="btn-group btn-group-sm" role="group"> <div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> @if ($canManipulate)
<i class="fa fa-fw fa-pencil"></i> <span class="caret"></span> <div class="btn-group btn-group-sm" role="group">
</button> <button type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<div class="dropdown-menu"> <i class="fa fa-fw fa-pencil"></i> <span class="caret"></span>
<a href="#" class="dropdown-item rotate-photo-left" v-on:click="rotateLeft"><i class="fa fa-fw fa-rotate-left"></i> @lang('admin.photo_actions.rotate_left')</a> </button>
<a href="#" class="dropdown-item rotate-photo-right" v-on:click="rotateRight"><i class="fa fa-fw fa-rotate-right"></i> @lang('admin.photo_actions.rotate_right')</a> <div class="dropdown-menu">
<div class="dropdown-divider"></div> <a href="#" class="dropdown-item rotate-photo-left" v-on:click="rotateLeft"><i class="fa fa-fw fa-rotate-left"></i> @lang('admin.photo_actions.rotate_left')</a>
<a href="#" class="dropdown-item flip-photo-horizontal" v-on:click="flipHorizontal"><i class="fa fa-fw fa-arrows-h"></i> @lang('admin.photo_actions.flip_horizontal')</a> <a href="#" class="dropdown-item rotate-photo-right" v-on:click="rotateRight"><i class="fa fa-fw fa-rotate-right"></i> @lang('admin.photo_actions.rotate_right')</a>
<a href="#" class="dropdown-item flip-photo-vertical" v-on:click="flipVertical"><i class="fa fa-fw fa-arrows-v"></i> @lang('admin.photo_actions.flip_vertical')</a> <div class="dropdown-divider"></div>
<a href="#" class="dropdown-item flip-photo-both" v-on:click="flipBoth"><i class="fa fa-fw fa-retweet"></i> @lang('admin.photo_actions.flip_both')</a> <a href="#" class="dropdown-item flip-photo-horizontal" v-on:click="flipHorizontal"><i class="fa fa-fw fa-arrows-h"></i> @lang('admin.photo_actions.flip_horizontal')</a>
<a href="#" class="dropdown-item flip-photo-vertical" v-on:click="flipVertical"><i class="fa fa-fw fa-arrows-v"></i> @lang('admin.photo_actions.flip_vertical')</a>
<a href="#" class="dropdown-item flip-photo-both" v-on:click="flipBoth"><i class="fa fa-fw fa-retweet"></i> @lang('admin.photo_actions.flip_both')</a>
</div>
</div>
@endif
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-fw fa-cog"></i> <span class="caret"></span>
</button>
<div class="dropdown-menu">
@if ($canChangeMetadata)
<a href="#" class="dropdown-item change-album" v-on:click="changeAlbum"><i class="fa fa-fw fa-share"></i> @lang('admin.photo_actions.change_album')</a>
<a href="#" class="dropdown-item regenerate-thumbnails" v-on:click="regenerateThumbnails"><i class="fa fa-fw fa-picture-o"></i> @lang('admin.photo_actions.refresh_thumbnails')</a>
@endif
@if ($canDelete)
<a href="#" class="dropdown-item delete-photo" v-on:click="deletePhoto"><i class="fa fa-fw fa-trash text-danger"></i> <span class="text-danger">@lang('admin.photo_actions.delete')</span></a>
@endif
</div>
</div> </div>
</div> </div>
<div class="btn-group" role="group"> <div class="mt-2">
<button type="button" class="btn btn-secondary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <input type="checkbox" id="select-photo-{{ $photo->id }}" name="select-photo[]" value="{{ $photo->id }}" v-bind:checked="isPhotoSelected({{ $photo->id }})" /> <label for="select-photo-{{ $photo->id }}">@lang('forms.select')</label>
<i class="fa fa-fw fa-cog"></i> <span class="caret"></span>
</button>
<div class="dropdown-menu">
<a href="#" class="dropdown-item change-album" v-on:click="changeAlbum"><i class="fa fa-fw fa-share"></i> @lang('admin.photo_actions.change_album')</a>
<a href="#" class="dropdown-item regenerate-thumbnails" v-on:click="regenerateThumbnails"><i class="fa fa-fw fa-picture-o"></i> @lang('admin.photo_actions.refresh_thumbnails')</a>
<a href="#" class="dropdown-item delete-photo" v-on:click="deletePhoto"><i class="fa fa-fw fa-trash text-danger"></i> <span class="text-danger">@lang('admin.photo_actions.delete')</span></a>
</div>
</div> </div>
</div> </div>
@endif
<div class="mt-2">
<input type="checkbox" id="select-photo-{{ $photo->id }}" name="select-photo[]" value="{{ $photo->id }}" v-bind:checked="isPhotoSelected({{ $photo->id }})" /> <label for="select-photo-{{ $photo->id }}">@lang('forms.select')</label>
</div>
</div>
</div> </div>
<div class="col-xs-12 col-sm-10"> <div class="col-xs-12 col-sm-10">
@php($validation_field_name = ('photo.' . $photo->id . '.name')) @php($validation_field_name = ('photo.' . $photo->id . '.name'))
<div class="form-group{{ $errors->has($validation_field_name) ? ' has-error' : '' }}"> <div class="form-group{{ $errors->has($validation_field_name) ? ' has-error' : '' }}">
<label class="control-label" name="{{ $field_prefix }}[name]">@lang('forms.name_label')</label> <label class="control-label" name="{{ $field_prefix }}[name]">@lang('forms.name_label')</label>
<input class="form-control" type="text" name="{{ $field_prefix }}[name]" value="{{ old('name', $photo->name) }}"/> <input class="form-control" type="text" name="{{ $field_prefix }}[name]" value="{{ old($field_prefix . '[name]', $photo->name) }}" @cannot('change-metadata', $photo) disabled="disabled"@endcannot/>
@if ($errors->has($validation_field_name)) @if ($errors->has($validation_field_name))
<span class="help-block"> <span class="help-block">
@ -57,7 +68,7 @@
<div class="form-group"> <div class="form-group">
<label class="control-label" name="{{ $field_prefix }}[description]">@lang('forms.description_label')</label> <label class="control-label" name="{{ $field_prefix }}[description]">@lang('forms.description_label')</label>
<textarea name="{{ $field_prefix }}[description]" class="form-control" rows="4">{{ old('name', $photo->description) }}</textarea> <textarea name="{{ $field_prefix }}[description]" class="form-control" rows="4" @cannot('change-metadata', $photo) disabled="disabled"@endcannot>{{ old($field_prefix . '[description]', $photo->description) }}</textarea>
</div> </div>
</div> </div>
</div> </div>