Merge pull request 'Introduce edit menu for admins' (#49) from edit-menu into master

Reviewed-on: Public/pics#49
This commit is contained in:
Aaron van Geffen 2024-02-24 13:10:58 +01:00
commit 2bfbe67d91
7 changed files with 189 additions and 69 deletions

View File

@ -30,6 +30,40 @@ class EditAsset extends HTMLController
header('Location: ' . $redirectUrl); header('Location: ' . $redirectUrl);
exit; exit;
} }
else
{
$isPrioChange = isset($_REQUEST['inc_prio']) || isset($_REQUEST['dec_prio']);
$isCoverChange = isset($_REQUEST['album_cover'], $_REQUEST['in']);
$madeChanges = false;
if ($user->isAdmin() && $isPrioChange && Session::validateSession('get'))
{
if (isset($_REQUEST['inc_prio']))
$priority = $asset->priority + 1;
else
$priority = $asset->priority - 1;
$asset->priority = max(0, min(100, $priority));
$asset->save();
$madeChanges = true;
}
elseif ($user->isAdmin() && $isCoverChange && Session::validateSession('get'))
{
$tag = Tag::fromId($_REQUEST['in']);
$tag->id_asset_thumb = $asset->getId();
$tag->save();
$madeChanges = true;
}
if ($madeChanges)
{
if (isset($_SERVER['HTTP_REFERER']))
header('Location: ' . $_SERVER['HTTP_REFERER']);
else
header('Location: ' . BASEURL . '/' . $asset->getSubdir());
exit;
}
}
// Get a list of available photo albums // Get a list of available photo albums
$allAlbums = []; $allAlbums = [];
@ -61,10 +95,12 @@ class EditAsset extends HTMLController
// Key info // Key info
if (isset($_POST['title'], $_POST['slug'], $_POST['date_captured'], $_POST['priority'])) if (isset($_POST['title'], $_POST['slug'], $_POST['date_captured'], $_POST['priority']))
{ {
$date_captured = !empty($_POST['date_captured']) ? $asset->date_captured = !empty($_POST['date_captured']) ?
new DateTime(str_replace('T', ' ', $_POST['date_captured'])) : null; new DateTime(str_replace('T', ' ', $_POST['date_captured'])) : null;
$slug = Asset::cleanSlug($_POST['slug']); $asset->slug = Asset::cleanSlug($_POST['slug']);
$asset->setKeyData(htmlspecialchars($_POST['title']), $slug, $date_captured, intval($_POST['priority'])); $asset->title = htmlspecialchars($_POST['title']);
$asset->priority = intval($_POST['priority']);
$asset->save();
} }
// Changing parent album? // Changing parent album?

View File

@ -107,8 +107,11 @@ class ViewPhotoAlbum extends HTMLController
if (!empty($active_filter)) if (!empty($active_filter))
$url_params['by'] = $active_filter; $url_params['by'] = $active_filter;
if (!empty($url_params)) $url_suffix = http_build_query($url_params);
$index->setUrlSuffix('?' . http_build_query($url_params)); $index->setUrlSuffix('?' . $url_suffix);
$menu_items = $this->getEditMenuItems('&' . $url_suffix);
$index->setEditMenuItems($menu_items);
} }
// Make a page index as needed, while we're at it. // Make a page index as needed, while we're at it.
@ -228,6 +231,46 @@ class ViewPhotoAlbum extends HTMLController
return $buttons; return $buttons;
} }
private function getEditMenuItems($url_suffix)
{
$items = [];
$sess = '&' . Session::getSessionTokenKey() . '=' . Session::getSessionToken();
if (Registry::get('user')->isLoggedIn())
{
$items[] = [
'label' => 'Edit image',
'uri' => fn($image) => $image->getEditUrl() . $url_suffix,
];
$items[] = [
'label' => 'Delete image',
'uri' => fn($image) => $image->getDeleteUrl() . $url_suffix . $sess,
'onclick' => 'return confirm(\'Are you sure you want to delete this image?\');',
];
}
if (Registry::get('user')->isAdmin())
{
$items[] = [
'label' => 'Make album cover',
'uri' => fn($image) => $image->getEditUrl() . $url_suffix . '&album_cover' . $sess,
];
$items[] = [
'label' => 'Increase priority',
'uri' => fn($image) => $image->getEditUrl() . $url_suffix . '&inc_prio' . $sess,
];
$items[] = [
'label' => 'Decrease priority',
'uri' => fn($image) => $image->getEditUrl() . $url_suffix . '&dec_prio' . $sess,
];
}
return $items;
}
private function getHeaderBox(Tag $tag) private function getHeaderBox(Tag $tag)
{ {
// Can we go up a level? // Can we go up a level?

View File

@ -8,17 +8,17 @@
class Asset class Asset
{ {
protected $id_asset; public $id_asset;
protected $id_user_uploaded; public $id_user_uploaded;
protected $subdir; public $subdir;
protected $filename; public $filename;
protected $title; public $title;
protected $slug; public $slug;
protected $mimetype; public $mimetype;
protected $image_width; public $image_width;
protected $image_height; public $image_height;
protected $date_captured; public $date_captured;
protected $priority; public $priority;
protected $meta; protected $meta;
protected $tags; protected $tags;
@ -36,6 +36,11 @@ class Asset
$this->date_captured = new DateTime($data['date_captured']); $this->date_captured = new DateTime($data['date_captured']);
} }
public function canBeEditedBy(User $user)
{
return $this->isOwnedBy($user) || $user->isAdmin();
}
public static function cleanSlug($slug) public static function cleanSlug($slug)
{ {
// Only alphanumerical chars, underscores and forward slashes are allowed // Only alphanumerical chars, underscores and forward slashes are allowed
@ -675,26 +680,26 @@ class Asset
FROM assets'); FROM assets');
} }
public function setKeyData($title, $slug, DateTime $date_captured = null, $priority) public function save()
{ {
$params = [ if (empty($this->id_asset))
'id_asset' => $this->id_asset, throw new UnexpectedValueException();
'title' => $title,
'slug' => $slug,
'priority' => $priority,
];
if (isset($date_captured))
$params['date_captured'] = $date_captured->format('Y-m-d H:i:s');
return Registry::get('db')->query(' return Registry::get('db')->query('
UPDATE assets UPDATE assets
SET title = {string:title}, SET id_asset = {int:id_asset},
slug = {string:slug},' . (isset($date_captured) ? ' id_user_uploaded = {int:id_user_uploaded},
date_captured = {datetime:date_captured},' : '') . ' subdir = {string:subdir},
filename = {string:filename},
title = {string:title},
slug = {string:slug},
mimetype = {string:mimetype},
image_width = {int:image_width},
image_height = {int:image_height},
date_captured = {datetime:date_captured},
priority = {int:priority} priority = {int:priority}
WHERE id_asset = {int:id_asset}', WHERE id_asset = {int:id_asset}',
$params); get_object_vars($this));
} }
protected function getUrlForAdjacentInSet($prevNext, ?Tag $tag, $activeFilter) protected function getUrlForAdjacentInSet($prevNext, ?Tag $tag, $activeFilter)

View File

@ -1,27 +1,3 @@
/* Edit icon on tiled grids
-----------------------------*/
.polaroid {
position: relative;
}
.polaroid a.edit {
background: var(--bs-body-bg);
border-radius: 3px;
box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
color: var(--bs-body-color);
opacity: 0;
left: 20px;
line-height: 1.5;
padding: 5px 10px;
position: absolute;
transition: 0.25s;
top: 20px;
z-index: 50;
}
.polaroid:hover > a.edit {
opacity: 1;
}
/* Crop editor /* Crop editor
----------------*/ ----------------*/
#crop_editor { #crop_editor {

View File

@ -296,6 +296,34 @@ div.polaroid a {
} }
/* Edit icon on tiled grids
-----------------------------*/
.polaroid {
position: relative;
}
.polaroid div.edit {
box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
opacity: 0;
left: 20px;
position: absolute;
transition: 0.25s;
top: 20px;
z-index: 50;
}
.polaroid div.edit .dropdown-item {
line-height: 1.4;
}
.polaroid div.edit .dropdown-toggle {
line-height: 1.4;
padding: 0.25rem 0.5rem;
}
.polaroid div.edit .dropdown-toggle::after {
margin-left: 0;
}
.polaroid:hover > div.edit {
opacity: 1;
}
/* Album title boxes /* Album title boxes
----------------------*/ ----------------------*/

View File

@ -25,7 +25,15 @@ class PhotoPage extends Template
echo ' echo '
<div class="row mt-5"> <div class="row mt-5">
<div class="col-lg-9"> <div class="col-lg">';
$this->photoMeta();
echo '
</div>
</div>
<div class="row mt-5">
<div class="col-lg">
<div id="sub_photo" class="content-box">'; <div id="sub_photo" class="content-box">';
$this->userActions(); $this->userActions();
@ -39,12 +47,6 @@ class PhotoPage extends Template
echo ' echo '
</div> </div>
</div> </div>
<div class="col-lg-3">';
$this->photoMeta();
echo '
</div>
</div> </div>
<script type="text/javascript" src="', BASEURL, '/js/photonav.js"></script>'; <script type="text/javascript" src="', BASEURL, '/js/photonav.js"></script>';
} }
@ -109,12 +111,12 @@ class PhotoPage extends Template
private function photoMeta() private function photoMeta()
{ {
echo ' echo '
<ul class="list-group photo_meta">'; <ul class="list-group list-group-horizontal photo_meta">';
foreach ($this->metaData as $header => $body) foreach ($this->metaData as $header => $body)
{ {
echo ' echo '
<li class="list-group-item"> <li class="list-group-item flex-fill">
<h4>', $header, '</h4> <h4>', $header, '</h4>
', $body, ' ', $body, '
</li>'; </li>';

View File

@ -13,7 +13,9 @@ class PhotosIndex extends Template
protected $show_headers; protected $show_headers;
protected $show_labels; protected $show_labels;
protected $previous_header = ''; protected $previous_header = '';
protected $url_suffix;
protected $edit_menu_items = [];
protected $photo_url_suffix;
const PANORAMA_WIDTH = 1256; const PANORAMA_WIDTH = 1256;
const PANORAMA_HEIGHT = null; const PANORAMA_HEIGHT = null;
@ -81,6 +83,30 @@ class PhotosIndex extends Template
$this->previous_header = $header; $this->previous_header = $header;
} }
protected function editMenu(Image $image)
{
if (empty($this->edit_menu_items))
return;
echo '
<div class="edit dropdown">
<button class="btn btn-primary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
</button>
<ul class="dropdown-menu">';
foreach ($this->edit_menu_items as $item)
{
echo '
<li><a class="dropdown-item" href="', $item['uri']($image), '"',
isset($item['onclick']) ? ' onclick="' . $item['onclick'] . '"' : '',
'>', $item['label'], '</a></li>';
}
echo '
</ul>
</div>';
}
protected function photo(Image $image, $className, $width, $height, $crop = true, $fit = true) protected function photo(Image $image, $className, $width, $height, $crop = true, $fit = true)
{ {
// Prefer thumbnail aspect ratio if available, otherwise use image aspect ratio. // Prefer thumbnail aspect ratio if available, otherwise use image aspect ratio.
@ -89,12 +115,11 @@ class PhotosIndex extends Template
echo ' echo '
<div class="polaroid ', $className, '" style="aspect-ratio: ', $aspectRatio, '">'; <div class="polaroid ', $className, '" style="aspect-ratio: ', $aspectRatio, '">';
if ($this->show_edit_buttons) if ($this->show_edit_buttons && $image->canBeEditedBy(Registry::get('user')))
echo ' $this->editMenu($image);
<a class="edit" href="', BASEURL, '/editasset/?id=', $image->getId(), '">Edit</a>';
echo ' echo '
<a href="', $image->getPageUrl(), $this->url_suffix, '#photo_frame">'; <a href="', $image->getPageUrl(), $this->photo_url_suffix, '#photo_frame">';
foreach (['normal-photo', 'blur-photo'] as $className) foreach (['normal-photo', 'blur-photo'] as $className)
@ -319,8 +344,13 @@ class PhotosIndex extends Template
$this->threePortraits($photos, $altLayout); $this->threePortraits($photos, $altLayout);
} }
public function setEditMenuItems(array $items)
{
$this->edit_menu_items = $items;
}
public function setUrlSuffix($suffix) public function setUrlSuffix($suffix)
{ {
$this->url_suffix = $suffix; $this->photo_url_suffix = $suffix;
} }
} }