Allow users to filter albums by contributors #48
@ -21,22 +21,30 @@ class Download
|
|||||||
$tag = (int)$_GET['tag'];
|
$tag = (int)$_GET['tag'];
|
||||||
$album = Tag::fromId($tag);
|
$album = Tag::fromId($tag);
|
||||||
|
|
||||||
|
if (isset($_GET['by']) && ($user = Member::fromSlug($_GET['by'])) !== false)
|
||||||
|
$id_user_uploaded = $user->getUserId();
|
||||||
|
else
|
||||||
|
$id_user_uploaded = null;
|
||||||
|
|
||||||
if (isset($_SESSION['current_export']))
|
if (isset($_SESSION['current_export']))
|
||||||
throw new UserFacingException('You can only export one album at the same time. Please wait until the other download finishes, or try again later.');
|
throw new UserFacingException('You can only export one album at the same time. Please wait until the other download finishes, or try again later.');
|
||||||
|
|
||||||
// So far so good?
|
// So far so good?
|
||||||
$this->exportAlbum($album);
|
$this->exportAlbum($album, $id_user_uploaded);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function exportAlbum(Tag $album)
|
private function exportAlbum(Tag $album, $id_user_uploaded)
|
||||||
{
|
{
|
||||||
$files = [];
|
$files = [];
|
||||||
|
|
||||||
$album_ids = array_merge([$album->id_tag], $this->getChildAlbumIds($album->id_tag));
|
$album_ids = array_merge([$album->id_tag], $this->getChildAlbumIds($album->id_tag));
|
||||||
foreach ($album_ids as $album_id)
|
foreach ($album_ids as $album_id)
|
||||||
{
|
{
|
||||||
$iterator = AssetIterator::getByOptions(['id_tag' => $album_id]);
|
$iterator = AssetIterator::getByOptions([
|
||||||
|
'id_tag' => $album_id,
|
||||||
|
'id_user_uploaded' => $id_user_uploaded,
|
||||||
|
]);
|
||||||
while ($asset = $iterator->next())
|
while ($asset = $iterator->next())
|
||||||
$files[] = join(DIRECTORY_SEPARATOR, [$asset->getSubdir(), $asset->getFilename()]);
|
$files[] = join(DIRECTORY_SEPARATOR, [$asset->getSubdir(), $asset->getFilename()]);
|
||||||
}
|
}
|
||||||
@ -71,6 +79,9 @@ class Download
|
|||||||
// STDOUT should not block.
|
// STDOUT should not block.
|
||||||
stream_set_blocking($pipes[1], 0);
|
stream_set_blocking($pipes[1], 0);
|
||||||
|
|
||||||
|
// Allow this the download to take its time...
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
header('Pragma: no-cache');
|
header('Pragma: no-cache');
|
||||||
header('Content-Description: File Download');
|
header('Content-Description: File Download');
|
||||||
header('Content-disposition: attachment; filename="' . $album->tag . '.tar"');
|
header('Content-disposition: attachment; filename="' . $album->tag . '.tar"');
|
||||||
|
@ -46,6 +46,18 @@ class ViewPhoto extends HTMLController
|
|||||||
if (isset($tag))
|
if (isset($tag))
|
||||||
$page->setTag($tag);
|
$page->setTag($tag);
|
||||||
|
|
||||||
|
// Keeping tabs on a filter?
|
||||||
|
if (isset($_GET['by']))
|
||||||
|
{
|
||||||
|
// Let's first verify that the filter is valid
|
||||||
|
$user = Member::fromSlug($_GET['by']);
|
||||||
|
if (!$user)
|
||||||
|
throw new UnexpectedValueException('Invalid filter for this album or tag.');
|
||||||
|
|
||||||
|
// Alright, let's run with it then
|
||||||
|
$page->setActiveFilter($user->getSlug());
|
||||||
|
}
|
||||||
|
|
||||||
$this->page->adopt($page);
|
$this->page->adopt($page);
|
||||||
$this->page->setCanonicalUrl($this->photo->getPageUrl());
|
$this->page->setCanonicalUrl($this->photo->getPageUrl());
|
||||||
}
|
}
|
||||||
|
@ -26,60 +26,89 @@ class ViewPhotoAlbum extends HTMLController
|
|||||||
$tag = Tag::fromSlug($_GET['tag']);
|
$tag = Tag::fromSlug($_GET['tag']);
|
||||||
$id_tag = $tag->id_tag;
|
$id_tag = $tag->id_tag;
|
||||||
$title = $tag->tag;
|
$title = $tag->tag;
|
||||||
$description = !empty($tag->description) ? $tag->description : '';
|
$header_box = $this->getHeaderBox($tag);
|
||||||
|
|
||||||
// Can we go up a level?
|
|
||||||
if ($tag->id_parent != 0)
|
|
||||||
{
|
|
||||||
$ptag = Tag::fromId($tag->id_parent);
|
|
||||||
$back_link = BASEURL . '/' . (!empty($ptag->slug) ? $ptag->slug . '/' : '');
|
|
||||||
$back_link_title = 'Back to "' . $ptag->tag . '"';
|
|
||||||
}
|
|
||||||
elseif ($tag->kind === 'Person')
|
|
||||||
{
|
|
||||||
$back_link = BASEURL . '/people/';
|
|
||||||
$back_link_title = 'Back to "People"';
|
|
||||||
$is_person = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$header_box = new AlbumHeaderBox($title, $description, $back_link, $back_link_title);
|
|
||||||
}
|
}
|
||||||
// View the album root.
|
// View the album root.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$id_tag = 1;
|
$id_tag = 1;
|
||||||
|
$tag = Tag::fromId($id_tag);
|
||||||
$title = 'Albums';
|
$title = 'Albums';
|
||||||
}
|
}
|
||||||
|
|
||||||
// What page are we at?
|
// What page are we at?
|
||||||
$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
|
$current_page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
|
||||||
|
|
||||||
parent::__construct($title . ' - Page ' . $page . ' - ' . SITE_TITLE);
|
parent::__construct($title . ' - Page ' . $current_page . ' - ' . SITE_TITLE);
|
||||||
if (isset($header_box))
|
if (isset($header_box))
|
||||||
$this->page->adopt($header_box);
|
$this->page->adopt($header_box);
|
||||||
|
|
||||||
// Can we do fancy things here?
|
// Who contributed to this album?
|
||||||
// !!! TODO: permission system?
|
$contributors = $tag->getContributorList();
|
||||||
$buttons = $this->getAlbumButtons($id_tag, $tag ?? null);
|
|
||||||
if (!empty($buttons))
|
// Enumerate possible filters
|
||||||
$this->page->adopt(new AlbumButtonBox($buttons));
|
$filters = [];
|
||||||
|
if (!empty($contributors))
|
||||||
|
{
|
||||||
|
$filters[''] = ['id_user' => null, 'label' => '', 'caption' => 'All photos',
|
||||||
Aaron marked this conversation as resolved
Outdated
|
|||||||
|
'link' => $tag->getUrl()];
|
||||||
|
|
||||||
|
foreach ($contributors as $contributor)
|
||||||
|
{
|
||||||
|
$filters[$contributor['slug']] = [
|
||||||
|
'id_user' => $contributor['id_user'],
|
||||||
|
'label' => $contributor['first_name'],
|
||||||
|
'caption' => sprintf('By %s (%s photos)',
|
||||||
|
$contributor['first_name'], $contributor['num_assets']),
|
||||||
|
'link' => $tag->getUrl() . '?by=' . $contributor['slug'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit to a particular uploader?
|
||||||
|
$active_filter = '';
|
||||||
|
$id_user_uploaded = null;
|
||||||
|
if (!empty($_GET['by']))
|
||||||
|
{
|
||||||
|
if (!isset($filters[$_GET['by']]))
|
||||||
|
throw new UnexpectedValueException('Invalid filter for this album or tag.');
|
||||||
|
|
||||||
|
$active_filter = $_GET['by'];
|
||||||
|
$id_user_uploaded = $filters[$active_filter]['id_user'];
|
||||||
|
$filters[$active_filter]['is_active'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an interface to query and modify the album/tag
|
||||||
|
$buttons = $this->getAlbumButtons($tag, $active_filter);
|
||||||
|
$button_strip = new AlbumButtonBox($buttons, $filters, $active_filter);
|
||||||
|
$this->page->adopt($button_strip);
|
||||||
|
|
||||||
// Fetch subalbums, but only if we're on the first page.
|
// Fetch subalbums, but only if we're on the first page.
|
||||||
if ($page === 1)
|
if ($current_page === 1)
|
||||||
{
|
{
|
||||||
$albums = $this->getAlbums($id_tag);
|
$albums = $this->getAlbums($id_tag);
|
||||||
$index = new AlbumIndex($albums);
|
$index = new AlbumIndex($albums);
|
||||||
$this->page->adopt($index);
|
$this->page->adopt($index);
|
||||||
}
|
}
|
||||||
|
|
||||||
Aaron marked this conversation as resolved
Outdated
minnozz
commented
(At $employer we had the convention to always use `$is_person` is never set
(At $employer we had the convention to always use `!== null` instead of `isset` when you expect the variable to exist to catch these kind of errors. `empty()` was also discouraged for this reason)
Aaron
commented
Yeah, I don't like this either. I've opted instead to explicitly declare it as a boolean before it's used. Yeah, I don't like this either. I've opted instead to explicitly declare it as a boolean before it's used.
|
|||||||
|
// Are we viewing a person tag?
|
||||||
|
$is_person = $tag->kind === 'Person';
|
||||||
|
|
||||||
// Load a photo mosaic for the current tag.
|
// Load a photo mosaic for the current tag.
|
||||||
list($mosaic, $total_count) = $this->getPhotoMosaic($id_tag, $page, !isset($is_person));
|
list($mosaic, $total_count) = $this->getPhotoMosaic($id_tag, $id_user_uploaded, $current_page, !$is_person);
|
||||||
if (isset($mosaic))
|
if (isset($mosaic))
|
||||||
{
|
{
|
||||||
$index = new PhotosIndex($mosaic, Registry::get('user')->isAdmin());
|
$index = new PhotosIndex($mosaic, Registry::get('user')->isAdmin());
|
||||||
$this->page->adopt($index);
|
$this->page->adopt($index);
|
||||||
if ($id_tag > 1)
|
|
||||||
$index->setUrlSuffix('?in=' . $id_tag);
|
$url_params = [];
|
||||||
|
if (isset($tag) && $tag->id_parent != 0)
|
||||||
|
$url_params['in'] = $tag->id_tag;
|
||||||
|
if (!empty($active_filter))
|
||||||
|
$url_params['by'] = $active_filter;
|
||||||
|
|
||||||
|
if (!empty($url_params))
|
||||||
|
$index->setUrlSuffix('?' . http_build_query($url_params));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a page index as needed, while we're at it.
|
// Make a page index as needed, while we're at it.
|
||||||
@ -88,24 +117,24 @@ class ViewPhotoAlbum extends HTMLController
|
|||||||
$index = new PageIndex([
|
$index = new PageIndex([
|
||||||
'recordCount' => $total_count,
|
'recordCount' => $total_count,
|
||||||
'items_per_page' => self::PER_PAGE,
|
'items_per_page' => self::PER_PAGE,
|
||||||
'start' => (isset($_GET['page']) ? $_GET['page'] - 1 : 0) * self::PER_PAGE,
|
'start' => ($current_page - 1) * self::PER_PAGE,
|
||||||
'base_url' => BASEURL . '/' . (isset($_GET['tag']) ? $_GET['tag'] . '/' : ''),
|
'base_url' => $tag->getUrl(),
|
||||||
'page_slug' => 'page/%PAGE%/',
|
'page_slug' => 'page/%PAGE%/' . (!empty($active_filter) ? '?by=' . $active_filter : ''),
|
||||||
'index_class' => 'pagination-lg justify-content-around justify-content-lg-center',
|
'index_class' => 'pagination-lg justify-content-around justify-content-lg-center',
|
||||||
]);
|
]);
|
||||||
$this->page->adopt(new PageIndexWidget($index));
|
$this->page->adopt(new PageIndexWidget($index));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the canonical url.
|
// Set the canonical url.
|
||||||
$this->page->setCanonicalUrl(BASEURL . '/' . (isset($_GET['tag']) ? $_GET['tag'] . '/' : '') .
|
$this->page->setCanonicalUrl($tag->getUrl() . ($current_page > 1 ? 'page/' . $current_page . '/' : ''));
|
||||||
($page > 1 ? 'page/' . $page . '/' : ''));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPhotoMosaic($id_tag, $page, $sort_linear)
|
public function getPhotoMosaic($id_tag, $id_user_uploaded, $page, $sort_linear)
|
||||||
{
|
{
|
||||||
// Create an iterator.
|
// Create an iterator.
|
||||||
list($this->iterator, $total_count) = AssetIterator::getByOptions([
|
list($this->iterator, $total_count) = AssetIterator::getByOptions([
|
||||||
'id_tag' => $id_tag,
|
'id_tag' => $id_tag,
|
||||||
|
'id_user_uploaded' => $id_user_uploaded,
|
||||||
'order' => 'date_captured',
|
'order' => 'date_captured',
|
||||||
'direction' => $sort_linear ? 'asc' : 'desc',
|
'direction' => $sort_linear ? 'asc' : 'desc',
|
||||||
'limit' => self::PER_PAGE,
|
'limit' => self::PER_PAGE,
|
||||||
@ -145,25 +174,26 @@ class ViewPhotoAlbum extends HTMLController
|
|||||||
return $albums;
|
return $albums;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getAlbumButtons($id_tag, $tag)
|
private function getAlbumButtons(Tag $tag, $active_filter)
|
||||||
{
|
{
|
||||||
$buttons = [];
|
$buttons = [];
|
||||||
$user = Registry::get('user');
|
$user = Registry::get('user');
|
||||||
|
|
||||||
if ($user->isLoggedIn())
|
if ($user->isLoggedIn())
|
||||||
{
|
{
|
||||||
|
$suffix = !empty($active_filter) ? '&by=' . $active_filter : '';
|
||||||
$buttons[] = [
|
$buttons[] = [
|
||||||
'url' => BASEURL . '/download/?tag=' . $id_tag,
|
'url' => BASEURL . '/download/?tag=' . $tag->id_tag . $suffix,
|
||||||
'caption' => 'Download album',
|
'caption' => 'Download album',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($tag))
|
if ($tag->id_parent != 0)
|
||||||
{
|
{
|
||||||
if ($tag->kind === 'Album')
|
if ($tag->kind === 'Album')
|
||||||
{
|
{
|
||||||
$buttons[] = [
|
$buttons[] = [
|
||||||
'url' => BASEURL . '/uploadmedia/?tag=' . $id_tag,
|
'url' => BASEURL . '/uploadmedia/?tag=' . $tag->id_tag,
|
||||||
'caption' => 'Upload photos here',
|
'caption' => 'Upload photos here',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -173,14 +203,14 @@ class ViewPhotoAlbum extends HTMLController
|
|||||||
if ($tag->kind === 'Album')
|
if ($tag->kind === 'Album')
|
||||||
{
|
{
|
||||||
$buttons[] = [
|
$buttons[] = [
|
||||||
'url' => BASEURL . '/editalbum/?id=' . $id_tag,
|
'url' => BASEURL . '/editalbum/?id=' . $tag->id_tag,
|
||||||
'caption' => 'Edit album',
|
'caption' => 'Edit album',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
elseif ($tag->kind === 'Person')
|
elseif ($tag->kind === 'Person')
|
||||||
{
|
{
|
||||||
$buttons[] = [
|
$buttons[] = [
|
||||||
'url' => BASEURL . '/edittag/?id=' . $id_tag,
|
'url' => BASEURL . '/edittag/?id=' . $tag->id_tag,
|
||||||
'caption' => 'Edit tag',
|
'caption' => 'Edit tag',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -190,7 +220,7 @@ class ViewPhotoAlbum extends HTMLController
|
|||||||
if ($user->isAdmin() && (!isset($tag) || $tag->kind === 'Album'))
|
if ($user->isAdmin() && (!isset($tag) || $tag->kind === 'Album'))
|
||||||
{
|
{
|
||||||
$buttons[] = [
|
$buttons[] = [
|
||||||
'url' => BASEURL . '/addalbum/?tag=' . $id_tag,
|
'url' => BASEURL . '/addalbum/?tag=' . $tag->id_tag,
|
||||||
'caption' => 'Create subalbum',
|
'caption' => 'Create subalbum',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -198,6 +228,25 @@ class ViewPhotoAlbum extends HTMLController
|
|||||||
return $buttons;
|
return $buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getHeaderBox(Tag $tag)
|
||||||
|
{
|
||||||
|
// Can we go up a level?
|
||||||
|
if ($tag->id_parent != 0)
|
||||||
|
{
|
||||||
|
$ptag = Tag::fromId($tag->id_parent);
|
||||||
|
$back_link = BASEURL . '/' . (!empty($ptag->slug) ? $ptag->slug . '/' : '');
|
||||||
|
$back_link_title = 'Back to "' . $ptag->tag . '"';
|
||||||
Aaron marked this conversation as resolved
minnozz
commented
Unused here Unused here
|
|||||||
|
}
|
||||||
|
elseif ($tag->kind === 'Person')
|
||||||
|
{
|
||||||
|
$back_link = BASEURL . '/people/';
|
||||||
|
$back_link_title = 'Back to "People"';
|
||||||
|
}
|
||||||
|
|
||||||
|
$description = !empty($tag->description) ? $tag->description : '';
|
||||||
|
return new AlbumHeaderBox($tag->tag, $description, $back_link, $back_link_title);
|
||||||
|
}
|
||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
if (isset($this->iterator))
|
if (isset($this->iterator))
|
||||||
|
114
models/Asset.php
114
models/Asset.php
@ -697,65 +697,79 @@ class Asset
|
|||||||
$params);
|
$params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlForPreviousInSet(?Tag $tag)
|
protected function getUrlForAdjacentInSet($prevNext, ?Tag $tag, $activeFilter)
|
||||||
{
|
{
|
||||||
$row = Registry::get('db')->queryAssoc('
|
$next = $prevNext === 'next';
|
||||||
SELECT a.*
|
$previous = !$next;
|
||||||
' . (isset($tag) ? '
|
|
||||||
FROM assets_tags AS t
|
|
||||||
INNER JOIN assets AS a ON a.id_asset = t.id_asset
|
|
||||||
WHERE t.id_tag = {int:id_tag} AND
|
|
||||||
(a.date_captured, a.id_asset) < ({datetime:date_captured}, {int:id_asset})
|
|
||||||
ORDER BY a.date_captured DESC, a.id_asset DESC'
|
|
||||||
: '
|
|
||||||
FROM assets AS a
|
|
||||||
WHERE (a.date_captured, a.id_asset) > ({datetime:date_captured}, {int:id_asset})
|
|
||||||
ORDER BY date_captured ASC, a.id_asset ASC')
|
|
||||||
. '
|
|
||||||
LIMIT 1',
|
|
||||||
[
|
|
||||||
'id_asset' => $this->id_asset,
|
|
||||||
'id_tag' => isset($tag) ? $tag->id_tag : null,
|
|
||||||
'date_captured' => $this->date_captured,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($row)
|
$where = [];
|
||||||
|
$params = [
|
||||||
|
'id_asset' => $this->id_asset,
|
||||||
|
'date_captured' => $this->date_captured,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Direction depends on whether we're browsing a tag or timeline
|
||||||
|
if (isset($tag))
|
||||||
{
|
{
|
||||||
$obj = self::byRow($row, 'object');
|
$where[] = 't.id_tag = {int:id_tag}';
|
||||||
return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : '');
|
$params['id_tag'] = $tag->id_tag;
|
||||||
|
$params['where_op'] = $previous ? '<' : '>';
|
||||||
|
$params['order_dir'] = $previous ? 'DESC' : 'ASC';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
$params['where_op'] = $previous ? '>' : '<';
|
||||||
|
$params['order_dir'] = $previous ? 'ASC' : 'DESC';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take active filter into account as well
|
||||||
|
if (!empty($activeFilter) && ($user = Member::fromSlug($activeFilter)) !== false)
|
||||||
|
{
|
||||||
|
$where[] = 'id_user_uploaded = {int:id_user_uploaded}';
|
||||||
|
$params['id_user_uploaded'] = $user->getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use complete ordering when sorting the set
|
||||||
|
$where[] = '(a.date_captured, a.id_asset) {raw:where_op} ' .
|
||||||
|
'({datetime:date_captured}, {int:id_asset})';
|
||||||
|
|
||||||
|
// Stringify conditions together
|
||||||
|
$where = '(' . implode(') AND (', $where) . ')';
|
||||||
|
|
||||||
|
// Run query, leaving out tags table if not required
|
||||||
|
$row = Registry::get('db')->queryAssoc('
|
||||||
|
SELECT a.*
|
||||||
|
FROM assets AS a
|
||||||
|
' . (isset($tag) ? '
|
||||||
|
INNER JOIN assets_tags AS t ON a.id_asset = t.id_asset' : '') . '
|
||||||
|
WHERE ' . $where . '
|
||||||
|
ORDER BY a.date_captured {raw:order_dir}, a.id_asset {raw:order_dir}
|
||||||
|
LIMIT 1',
|
||||||
|
$params);
|
||||||
|
|
||||||
|
if (!$row)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
$obj = self::byRow($row, 'object');
|
||||||
|
|
||||||
|
$urlParams = [];
|
||||||
|
if (isset($tag))
|
||||||
|
$urlParams['in'] = $tag->id_tag;
|
||||||
|
if (!empty($activeFilter))
|
||||||
|
$urlParams['by'] = $activeFilter;
|
||||||
|
|
||||||
|
$queryString = !empty($urlParams) ? '?' . http_build_query($urlParams) : '';
|
||||||
|
|
||||||
|
return $obj->getPageUrl() . $queryString;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlForNextInSet(?Tag $tag)
|
public function getUrlForPreviousInSet(?Tag $tag, $activeFilter)
|
||||||
{
|
{
|
||||||
$row = Registry::get('db')->queryAssoc('
|
return $this->getUrlForAdjacentInSet('previous', $tag, $activeFilter);
|
||||||
SELECT a.*
|
}
|
||||||
' . (isset($tag) ? '
|
|
||||||
FROM assets_tags AS t
|
|
||||||
INNER JOIN assets AS a ON a.id_asset = t.id_asset
|
|
||||||
WHERE t.id_tag = {int:id_tag} AND
|
|
||||||
(a.date_captured, a.id_asset) > ({datetime:date_captured}, {int:id_asset})
|
|
||||||
ORDER BY a.date_captured ASC, a.id_asset ASC'
|
|
||||||
: '
|
|
||||||
FROM assets AS a
|
|
||||||
WHERE (a.date_captured, a.id_asset) < ({datetime:date_captured}, {int:id_asset})
|
|
||||||
ORDER BY date_captured DESC, a.id_asset DESC')
|
|
||||||
. '
|
|
||||||
LIMIT 1',
|
|
||||||
[
|
|
||||||
'id_asset' => $this->id_asset,
|
|
||||||
'id_tag' => isset($tag) ? $tag->id_tag : null,
|
|
||||||
'date_captured' => $this->date_captured,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($row)
|
public function getUrlForNextInSet(?Tag $tag, $activeFilter)
|
||||||
{
|
{
|
||||||
$obj = self::byRow($row, 'object');
|
return $this->getUrlForAdjacentInSet('next', $tag, $activeFilter);
|
||||||
return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : '');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,11 @@ class AssetIterator extends Asset
|
|||||||
else
|
else
|
||||||
$where[] = 'a.mimetype = {string:mime_type}';
|
$where[] = 'a.mimetype = {string:mime_type}';
|
||||||
}
|
}
|
||||||
|
if (isset($options['id_user_uploaded']))
|
||||||
|
{
|
||||||
|
$params['id_user_uploaded'] = $options['id_user_uploaded'];
|
||||||
|
$where[] = 'id_user_uploaded = {int:id_user_uploaded}';
|
||||||
|
}
|
||||||
if (isset($options['id_tag']))
|
if (isset($options['id_tag']))
|
||||||
{
|
{
|
||||||
$params['id_tag'] = $options['id_tag'];
|
$params['id_tag'] = $options['id_tag'];
|
||||||
|
@ -155,24 +155,20 @@ class PageIndex
|
|||||||
|
|
||||||
public function getLink($start = null, $order = null, $dir = null)
|
public function getLink($start = null, $order = null, $dir = null)
|
||||||
{
|
{
|
||||||
$url = $this->base_url;
|
$page = !is_string($start) ? ($start / $this->items_per_page) + 1 : $start;
|
||||||
$amp = strpos($this->base_url, '?') ? '&' : '?';
|
$url = $this->base_url . str_replace('%PAGE%', $page, $this->page_slug);
|
||||||
|
|
||||||
if (!empty($start))
|
$urlParams = [];
|
||||||
{
|
|
||||||
$page = $start !== '%d' ? ($start / $this->items_per_page) + 1 : $start;
|
|
||||||
$url .= strtr($this->page_slug, ['%PAGE%' => $page, '%AMP%' => $amp]);
|
|
||||||
$amp = '&';
|
|
||||||
}
|
|
||||||
if (!empty($order))
|
if (!empty($order))
|
||||||
{
|
$urlParams['order'] = $order;
|
||||||
$url .= $amp . 'order=' . $order;
|
|
||||||
$amp = '&';
|
|
||||||
}
|
|
||||||
if (!empty($dir))
|
if (!empty($dir))
|
||||||
|
$urlParams['dir'] = $dir;
|
||||||
|
|
||||||
|
if (!empty($urlParams))
|
||||||
{
|
{
|
||||||
$url .= $amp . 'dir=' . $dir;
|
$queryString = (strpos($uri, '?') !== false ? '&' : '?');
|
||||||
$amp = '&';
|
$queryString .= http_build_query($urlParams);
|
||||||
|
$url .= $queryString;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $url;
|
return $url;
|
||||||
|
@ -141,6 +141,21 @@ class Tag
|
|||||||
return $rows;
|
return $rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getContributorList()
|
||||||
|
{
|
||||||
|
return Registry::get('db')->queryPairs('
|
||||||
|
SELECT u.id_user, u.first_name, u.surname, u.slug, COUNT(*) AS num_assets
|
||||||
|
FROM assets_tags AS at
|
||||||
|
LEFT JOIN assets AS a ON at.id_asset = a.id_asset
|
||||||
|
LEFT JOIN users AS u ON a.id_user_uploaded = u.id_user
|
||||||
|
WHERE at.id_tag = {int:id_tag}
|
||||||
|
GROUP BY a.id_user_uploaded
|
||||||
|
ORDER BY u.first_name, u.surname',
|
||||||
|
[
|
||||||
|
'id_tag' => $this->id_tag,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getPeople($id_parent = 0, $offset = 0, $limit = 24, $return_format = 'array')
|
public static function getPeople($id_parent = 0, $offset = 0, $limit = 24, $return_format = 'array')
|
||||||
{
|
{
|
||||||
$rows = Registry::get('db')->queryAssocs('
|
$rows = Registry::get('db')->queryAssocs('
|
||||||
|
@ -75,6 +75,11 @@ abstract class User
|
|||||||
return $this->ip_address;
|
return $this->ip_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSlug()
|
||||||
|
{
|
||||||
|
return $this->slug;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether user is logged in.
|
* Returns whether user is logged in.
|
||||||
*/
|
*/
|
||||||
|
@ -339,9 +339,11 @@ div.polaroid a {
|
|||||||
---------------------*/
|
---------------------*/
|
||||||
.album_button_box {
|
.album_button_box {
|
||||||
float: right;
|
float: right;
|
||||||
|
display: flex;
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
.album_button_box > a {
|
.album_button_box > a,
|
||||||
|
.album_button_box .btn {
|
||||||
background: var(--bs-body-bg);
|
background: var(--bs-body-bg);
|
||||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
border-color: var( --bs-secondary-bg);
|
border-color: var( --bs-secondary-bg);
|
||||||
@ -349,7 +351,9 @@ div.polaroid a {
|
|||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
}
|
}
|
||||||
.album_button_box > a:hover {
|
.album_button_box > a:hover,
|
||||||
|
.album_button_box .btn:hover,
|
||||||
|
.album_button_box .btn:focus {
|
||||||
background: var(--bs-secondary-bg);
|
background: var(--bs-secondary-bg);
|
||||||
border-color: var(--bs-tertiary-bg);
|
border-color: var(--bs-tertiary-bg);
|
||||||
color: var(--bs-secondary-color);
|
color: var(--bs-secondary-color);
|
||||||
|
@ -8,11 +8,15 @@
|
|||||||
|
|
||||||
class AlbumButtonBox extends Template
|
class AlbumButtonBox extends Template
|
||||||
{
|
{
|
||||||
|
private $active_filter;
|
||||||
private $buttons;
|
private $buttons;
|
||||||
|
private $filters;
|
||||||
|
|
||||||
public function __construct($buttons)
|
public function __construct(array $buttons, array $filters, $active_filter)
|
||||||
{
|
{
|
||||||
|
$this->active_filter = $active_filter;
|
||||||
$this->buttons = $buttons;
|
$this->buttons = $buttons;
|
||||||
|
$this->filters = $filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function html_main()
|
public function html_main()
|
||||||
@ -24,6 +28,39 @@ class AlbumButtonBox extends Template
|
|||||||
echo '
|
echo '
|
||||||
<a class="btn btn-light" href="', $button['url'], '">', $button['caption'], '</a>';
|
<a class="btn btn-light" href="', $button['url'], '">', $button['caption'], '</a>';
|
||||||
|
|
||||||
|
if (!empty($this->filters))
|
||||||
|
{
|
||||||
|
echo '
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-light dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<i class="bi bi-filter"></i>';
|
||||||
|
|
||||||
|
if ($this->active_filter)
|
||||||
|
{
|
||||||
|
echo '
|
||||||
|
<span class="badge text-bg-danger">',
|
||||||
|
$this->filters[$this->active_filter]['label'], '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">';
|
||||||
|
|
||||||
|
foreach ($this->filters as $key => $filter)
|
||||||
|
{
|
||||||
|
$is_active = $key === $this->active_filter;
|
||||||
|
echo '
|
||||||
|
<li><a class="dropdown-item', $is_active ? ' active' : '',
|
||||||
|
'" href="', $filter['link'], '">',
|
||||||
|
$filter['caption'],
|
||||||
|
'</a></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '
|
||||||
|
</ul>
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
echo '
|
echo '
|
||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
class PhotoPage extends Template
|
class PhotoPage extends Template
|
||||||
{
|
{
|
||||||
|
private $activeFilter;
|
||||||
private $photo;
|
private $photo;
|
||||||
private $metaData;
|
private $metaData;
|
||||||
private $tag;
|
private $tag;
|
||||||
@ -78,6 +79,11 @@ class PhotoPage extends Template
|
|||||||
</a>';
|
</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setActiveFilter($filter)
|
||||||
|
{
|
||||||
|
$this->activeFilter = $filter;
|
||||||
|
}
|
||||||
|
|
||||||
public function setTag(Tag $tag)
|
public function setTag(Tag $tag)
|
||||||
{
|
{
|
||||||
$this->tag = $tag;
|
$this->tag = $tag;
|
||||||
@ -85,14 +91,14 @@ class PhotoPage extends Template
|
|||||||
|
|
||||||
private function photoNav()
|
private function photoNav()
|
||||||
{
|
{
|
||||||
if ($previousUrl = $this->photo->getUrlForPreviousInSet($this->tag))
|
if ($previousUrl = $this->photo->getUrlForPreviousInSet($this->tag, $this->activeFilter))
|
||||||
echo '
|
echo '
|
||||||
<a href="', $previousUrl, '#photo_frame" id="previous_photo"><i class="bi bi-arrow-left"></i></a>';
|
<a href="', $previousUrl, '#photo_frame" id="previous_photo"><i class="bi bi-arrow-left"></i></a>';
|
||||||
else
|
else
|
||||||
echo '
|
echo '
|
||||||
<span id="previous_photo"><i class="bi bi-arrow-left"></i></span>';
|
<span id="previous_photo"><i class="bi bi-arrow-left"></i></span>';
|
||||||
|
|
||||||
if ($nextUrl = $this->photo->getUrlForNextInSet($this->tag))
|
if ($nextUrl = $this->photo->getUrlForNextInSet($this->tag, $this->activeFilter))
|
||||||
echo '
|
echo '
|
||||||
<a href="', $nextUrl, '#photo_frame" id="next_photo"><i class="bi bi-arrow-right"></i></a>';
|
<a href="', $nextUrl, '#photo_frame" id="next_photo"><i class="bi bi-arrow-right"></i></a>';
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user
Key
label
missingI initially didn't add it as it'd never be used. You're right, though, and it's better to just have it there for consistency.