Changes the ConfirmDelete page and updates database code.

The ConfirmDelete page now uses parts of the photopage. The
Confirmation dialog is its own template which is based on Alert.

The database now updates the album thumb to the most recent
addition to the album, when the album thumb asset is being deleted.
When there are no pictures left in the album 0 will be set.
This commit is contained in:
Dennis Brentjes 2018-07-08 08:19:37 +00:00
parent e40c05c1f8
commit 16ec547064
12 changed files with 197 additions and 113 deletions

View File

@ -1,43 +0,0 @@
<?php
/*****************************************************************************
* ConfirmDelete.php
* Contains the ConfirmDelete controller
*
* Kabuki CMS (C) 2013-2016, Aaron van Geffen
*****************************************************************************/
class ConfirmDelete extends HTMLController
{
public function __construct()
{
// Ensure we're logged in at this point.
$user = Registry::get('user');
if (!$user->isLoggedIn())
throw new NotAllowedException();
$photo = Asset::fromSlug($_GET['slug']);
if (empty($photo))
throw new NotFoundException();
$author = $photo->getAuthor();
if (!($user->isAdmin() || $user->getUserId() === $author->getUserId()))
throw new NotAllowedException();
if (isset($_REQUEST['confirmed']))
$this->handleDelete($photo);
parent::__construct('Confirm deletion' . ' - ' . SITE_TITLE);
$page = new ConfirmDeletePage($photo->getImage());
$this->page->adopt($page);
}
private function handleDelete(Asset $photo) {
$album_url = $photo->getSubdir();
$photo->delete();
header('Location: ' . BASEURL . '/' . $album_url);
exit;
}
}

View File

@ -11,17 +11,53 @@ class ViewPhoto extends HTMLController
public function __construct() public function __construct()
{ {
// Ensure we're logged in at this point. // Ensure we're logged in at this point.
if (!Registry::get('user')->isLoggedIn()) $user = Registry::get('user');
if (!$user->isLoggedIn())
throw new NotAllowedException(); throw new NotAllowedException();
$photo = Asset::fromSlug($_GET['slug']); $photo = Asset::fromSlug($_GET['slug']);
if (empty($photo)) if (empty($photo))
throw new NotFoundException(); throw new NotFoundException();
parent::__construct($photo->getTitle() . ' - ' . SITE_TITLE);
$author = $photo->getAuthor();
if (isset($_REQUEST['confirm_delete']) || isset($_REQUEST['delete_confirmed']))
$this->handleConfirmDelete($user, $author, $photo);
else
$this->handleViewPhoto($user, $author, $photo);
// Add an edit button to the admin bar.
if ($user->isAdmin())
$this->admin_bar->appendItem(BASEURL . '/editasset/?id=' . $photo->getId(), 'Edit this photo');
}
private function handleConfirmDelete(User $user, User $author, Asset $photo)
{
if (!($user->isAdmin() || $user->getUserId() === $author->getUserId()))
throw new NotAllowedException();
if (isset($_REQUEST['confirm_delete']))
{
$page = new ConfirmDeletePage($photo->getImage());
$this->page->adopt($page);
}
else if (isset($_REQUEST['delete_confirmed']))
{
$album_url = $photo->getSubdir();
$photo->delete();
header('Location: ' . BASEURL . '/' . $album_url);
exit;
}
}
private function handleViewPhoto(User $user, User $author, Asset $photo)
{
if (!empty($_POST)) if (!empty($_POST))
$this->handleTagging($photo->getImage()); $this->handleTagging($photo->getImage());
parent::__construct($photo->getTitle() . ' - ' . SITE_TITLE);
$page = new PhotoPage($photo->getImage()); $page = new PhotoPage($photo->getImage());
// Exif data? // Exif data?
@ -43,17 +79,11 @@ class ViewPhoto extends HTMLController
if ($next_url) if ($next_url)
$page->setNextPhotoUrl($next_url); $page->setNextPhotoUrl($next_url);
$user = Registry::get('user');
$author = $photo->getAuthor();
if ($user->isAdmin() || $user->getUserId() === $author->getUserId()) if ($user->isAdmin() || $user->getUserId() === $author->getUserId())
$page->setIsAssetOwner(true); $page->setIsAssetOwner(true);
$this->page->adopt($page); $this->page->adopt($page);
$this->page->setCanonicalUrl($photo->getPageUrl()); $this->page->setCanonicalUrl($photo->getPageUrl());
// Add an edit button to the admin bar.
if (Registry::get('user')->isAdmin())
$this->admin_bar->appendItem(BASEURL . '/editasset/?id=' . $photo->getId(), 'Edit this photo');
} }
private function handleTagging(Image $photo) private function handleTagging(Image $photo)

View File

@ -485,14 +485,6 @@ class Asset
if (!unlink(ASSETSDIR . '/' . $this->subdir . '/' . $this->filename)) if (!unlink(ASSETSDIR . '/' . $this->subdir . '/' . $this->filename))
return false; return false;
$db->query('
UPDATE tags
SET id_asset_thumb = 0
WHERE id_asset_thumb = {int:id_asset} AND kind = "Album"',
[
'id_asset' => $this->id_asset,
]);
$db->query(' $db->query('
DELETE FROM assets_meta DELETE FROM assets_meta
WHERE id_asset = {int:id_asset}', WHERE id_asset = {int:id_asset}',
@ -500,12 +492,53 @@ class Asset
'id_asset' => $this->id_asset, 'id_asset' => $this->id_asset,
]); ]);
return $db->query(' $rows = $db->query('
SELECT id_tag
FROM assets_tags
WHERE id_asset = {int:id_asset}',
[
'id_asset' => $this->id_asset,
]);
$recount_tags = [];
if(!empty($rows))
foreach($rows as $row)
$recount_tags[] = $row['id_tag'];
$db->query('
DELETE FROM assets_tags
WHERE id_asset = {int:id_asset}',
[
'id_asset' => $this->id_asset,
]);
Tag::recount($recount_tags);
$return = $db->query('
DELETE FROM assets DELETE FROM assets
WHERE id_asset = {int:id_asset}', WHERE id_asset = {int:id_asset}',
[ [
'id_asset' => $this->id_asset, 'id_asset' => $this->id_asset,
]); ]);
$rows = $db->query('
SELECT id_tag
FROM tags
WHERE id_asset_thumb = {int:id_asset} AND kind = "Album"',
[
'id_asset' => $this->id_asset,
]);
if (!empty($rows))
{
foreach ($rows as $row)
{
$tag = Tag::fromId($row['id_tag']);
$tag->resetIdAsset();
}
}
return $return;
} }
public function linkTags(array $id_tags) public function linkTags(array $id_tags)

View File

@ -28,7 +28,6 @@ class Dispatcher
'suggest' => 'ProvideAutoSuggest', 'suggest' => 'ProvideAutoSuggest',
'timeline' => 'ViewTimeline', 'timeline' => 'ViewTimeline',
'uploadmedia' => 'UploadMedia', 'uploadmedia' => 'UploadMedia',
'confirmdelete' => 'ConfirmDelete',
]; ];
// Work around PHP's FPM not always providing PATH_INFO. // Work around PHP's FPM not always providing PATH_INFO.

View File

@ -289,6 +289,34 @@ class Tag
]); ]);
} }
public function resetIdAsset()
{
$db = Registry::get('db');
$row = $db->query('
SELECT MAX(id_asset) as new_id
FROM assets_tags
WHERE id_tag = {int:id_tag}',
[
'id_tag' => $this->id_tag,
]);
$new_id = 0;
if(!empty($row))
{
$new_id = $row->fetch_assoc()['new_id'];
}
return $db->query('
UPDATE tags
SET id_asset_thumb = {int:new_id}
WHERE id_tag = {int:id_tag}',
[
'new_id' => $new_id,
'id_tag' => $this->id_tag,
]);
}
public static function match($tokens) public static function match($tokens)
{ {
if (!is_array($tokens)) if (!is_array($tokens))

View File

@ -8,10 +8,10 @@
@import url(//fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,700italic); @import url(//fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,700italic);
@font-face { @font-face {
font-family: 'Invaders'; font-family: 'Invaders';
src: url('fonts/invaders.ttf') format('truetype'); src: url('fonts/invaders.ttf') format('truetype');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
body { body {
@ -135,7 +135,7 @@ ul#nav li a:hover {
} }
.pagination .page-padding { .pagination .page-padding {
cursor: pointer; cursor: pointer;
} }
@ -565,7 +565,7 @@ a#previous_photo:hover, a#next_photo:hover {
content: '→'; content: '→';
} }
#sub_photo h2, #sub_photo h3, #photo_exif_box h3 { #sub_photo h2, #sub_photo h3, #photo_exif_box h3, #user_actions_box h3 {
font: 600 20px/30px "Open Sans", sans-serif; font: 600 20px/30px "Open Sans", sans-serif;
margin: 0 0 10px; margin: 0 0 10px;
} }
@ -622,22 +622,13 @@ a#previous_photo:hover, a#next_photo:hover {
#user_actions_box { #user_actions_box {
background: #fff; background: #fff;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
float: left;
margin: 25px 0 25px 0; margin: 25px 0 25px 0;
overflow: auto; overflow: auto;
padding: 2%; padding: 2%;
float: right;
width: 20%; width: 20%;
} }
#confirm_box {
background: #fff;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
padding: 2%;
margin: 25px 0 25px 0;
text-align: center;
}
/* Responsive: smartphone in portrait /* Responsive: smartphone in portrait
---------------------------------------*/ ---------------------------------------*/
@media only screen and (max-width: 895px) { @media only screen and (max-width: 895px) {

View File

@ -19,6 +19,13 @@ class Alert extends SubTemplate
{ {
echo ' echo '
<div class="alert', $this->_type != 'alert' ? ' alert-' . $this->_type : '', '">', (!empty($this->_title) ? ' <div class="alert', $this->_type != 'alert' ? ' alert-' . $this->_type : '', '">', (!empty($this->_title) ? '
<strong>' . $this->_title . '</strong><br>' : ''), $this->_message, '</div>'; <strong>' . $this->_title . '</strong><br>' : ''), '<p>', $this->_message, '</p>';
$this->additional_alert_content();
echo '</div>';
} }
protected function additional_alert_content()
{}
} }

27
templates/Button.php Normal file
View File

@ -0,0 +1,27 @@
<?php
/*****************************************************************************
* Button.php
* Defines the Button template.
*
* Kabuki CMS (C) 2013-2015, Aaron van Geffen
*****************************************************************************/
class Button extends SubTemplate
{
private $content = '';
private $href = '';
private $class = '';
public function __construct($content = '', $href = '', $class = '')
{
$this->content = $content;
$this->href = $href;
$this->class = $class;
}
protected function html_content()
{
echo '
<a class="', $this->class, '" href="', $this->href, '">', $this->content, '</a>';
}
}

View File

@ -6,13 +6,11 @@
* Kabuki CMS (C) 2013-2016, Aaron van Geffen * Kabuki CMS (C) 2013-2016, Aaron van Geffen
*****************************************************************************/ *****************************************************************************/
class ConfirmDeletePage extends SubTemplate class ConfirmDeletePage extends PhotoPage
{ {
private $photo;
public function __construct(Image $photo) public function __construct(Image $photo)
{ {
$this->photo = $photo; parent::__construct($photo);
} }
protected function html_content() protected function html_content()
@ -23,30 +21,15 @@ class ConfirmDeletePage extends SubTemplate
private function confirm() private function confirm()
{ {
echo ' $buttons = [];
<div id=confirm_box> $buttons[] = new Button("Delete", BASEURL . '/' . $this->photo->getSlug() . '?delete_confirmed', "btn btn-red");
<h1>Confirm deletion</h1> $buttons[] = new Button("Cancel", $this->photo->getPageUrl(), "btn");
<p>You are about to permanently delete the following photo.</p>
<a class="btn btn-red" href="', BASEURL, '/confirmdelete?slug=', $this->photo->getSlug(), '&confirmed">Delete</a>
<a class="btn" href="', $this->photo->getPageUrl(), '"> Cancel</a>
</div>';
}
private function photo() $alert = new WarningDialog(
{ "Confirm deletion.",
echo ' "You are about to permanently delete the following photo.",
<div id="photo_frame"> $buttons
<a href="', $this->photo->getUrl(), '">'; );
$alert->html_content();
if ($this->photo->isPortrait())
echo '
<img src="', $this->photo->getThumbnailUrl(null, 960), '" alt="">';
else
echo '
<img src="', $this->photo->getThumbnailUrl(1280, null), '" alt="">';
echo '
</a>
</div>';
} }
} }

View File

@ -23,7 +23,7 @@ class EditAssetForm extends SubTemplate
<form id="asset_form" action="" method="post" enctype="multipart/form-data"> <form id="asset_form" action="" method="post" enctype="multipart/form-data">
<div class="boxed_content" style="margin-bottom: 2%"> <div class="boxed_content" style="margin-bottom: 2%">
<div style="float: right"> <div style="float: right">
<a class="btn btn-red" href="', BASEURL, '/confirmdelete?slug=', $this->asset->getSlug(), '>Delete asset</a> <a class="btn btn-red" href="', BASEURL, '/', $this->asset->getSlug(), '?delete_confirmed">Delete asset</a>
<input type="submit" value="Save asset data"> <input type="submit" value="Save asset data">
</div> </div>
<h2>Edit asset \'', $this->asset->getTitle(), '\' (', $this->asset->getFilename(), ')</h2> <h2>Edit asset \'', $this->asset->getTitle(), '\' (', $this->asset->getFilename(), ')</h2>

View File

@ -8,7 +8,7 @@
class PhotoPage extends SubTemplate class PhotoPage extends SubTemplate
{ {
private $photo; protected $photo;
private $exif; private $exif;
private $previous_photo_url = ''; private $previous_photo_url = '';
private $next_photo_url = ''; private $next_photo_url = '';
@ -29,7 +29,8 @@ class PhotoPage extends SubTemplate
$this->next_photo_url = $url; $this->next_photo_url = $url;
} }
public function setIsAssetOwner($flag) { public function setIsAssetOwner($flag)
{
$this->is_asset_owner = $flag; $this->is_asset_owner = $flag;
} }
@ -50,15 +51,14 @@ class PhotoPage extends SubTemplate
$this->photoMeta(); $this->photoMeta();
if($this->is_asset_owner) { if($this->is_asset_owner)
$this->addUserActions(); $this->addUserActions();
}
echo ' echo '
<script type="text/javascript" src="', BASEURL, '/js/photonav.js"></script>'; <script type="text/javascript" src="', BASEURL, '/js/photonav.js"></script>';
} }
private function photo() protected function photo()
{ {
echo ' echo '
<div id="photo_frame"> <div id="photo_frame">
@ -198,7 +198,7 @@ class PhotoPage extends SubTemplate
echo ' echo '
<div id=user_actions_box> <div id=user_actions_box>
<h3>Actions</h3> <h3>Actions</h3>
<a class="btn btn-red" href="', BASEURL, '/confirmdelete?slug=', $this->photo->getSlug(), '">Delete</a> <a class="btn btn-red" href="', BASEURL, '/', $this->photo->getSlug(), '?confirm_delete">Delete</a>
</div>'; </div>';
} }
} }

View File

@ -0,0 +1,29 @@
<?php
/*****************************************************************************
* WarningDialog.php
* Defines the WarningDialog template.
*
* Kabuki CMS (C) 2013-2015, Aaron van Geffen
*****************************************************************************/
class WarningDialog extends Alert
{
protected $buttons;
public function __construct($title = '', $message = '', $buttons = [])
{
parent::__construct($title, $message);
$this->buttons = $buttons;
}
protected function additional_alert_content()
{
$this->addButtons();
}
private function addButtons()
{
foreach ($this->buttons as $button)
$button->html_content();
}
}