From 08cdbfe7b6629f71f23bbe31ddd3b92c832b918e Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 14 Jan 2024 20:22:23 +0100 Subject: [PATCH 01/18] ViewPhotoAlbum: move some logic into new prepareHeaderBox method --- controllers/ViewPhotoAlbum.php | 38 +++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index 6524c86..139b560 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -26,23 +26,7 @@ class ViewPhotoAlbum extends HTMLController $tag = Tag::fromSlug($_GET['tag']); $id_tag = $tag->id_tag; $title = $tag->tag; - $description = !empty($tag->description) ? $tag->description : ''; - - // 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); + $header_box = $this->getHeaderBox($tag); } // View the album root. else @@ -198,6 +182,26 @@ class ViewPhotoAlbum extends HTMLController 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 . '"'; + } + elseif ($tag->kind === 'Person') + { + $back_link = BASEURL . '/people/'; + $back_link_title = 'Back to "People"'; + $is_person = true; + } + + $description = !empty($tag->description) ? $tag->description : ''; + return new AlbumHeaderBox($tag->tag, $description, $back_link, $back_link_title); + } + public function __destruct() { if (isset($this->iterator)) From 25b95286287fee62ce001f8cfc8af7705c2b28e8 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 14 Jan 2024 20:24:59 +0100 Subject: [PATCH 02/18] ViewPhotoAlbum: simplify tag handling in getAlbumButtons --- controllers/ViewPhotoAlbum.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index 139b560..b74006f 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -32,6 +32,7 @@ class ViewPhotoAlbum extends HTMLController else { $id_tag = 1; + $tag = Tag::fromId($id_tag); $title = 'Albums'; } @@ -44,7 +45,7 @@ class ViewPhotoAlbum extends HTMLController // Can we do fancy things here? // !!! TODO: permission system? - $buttons = $this->getAlbumButtons($id_tag, $tag ?? null); + $buttons = $this->getAlbumButtons($tag); if (!empty($buttons)) $this->page->adopt(new AlbumButtonBox($buttons)); @@ -129,7 +130,7 @@ class ViewPhotoAlbum extends HTMLController return $albums; } - private function getAlbumButtons($id_tag, $tag) + private function getAlbumButtons(Tag $tag) { $buttons = []; $user = Registry::get('user'); @@ -137,17 +138,17 @@ class ViewPhotoAlbum extends HTMLController if ($user->isLoggedIn()) { $buttons[] = [ - 'url' => BASEURL . '/download/?tag=' . $id_tag, + 'url' => BASEURL . '/download/?tag=' . $tag->id_tag, 'caption' => 'Download album', ]; } - if (isset($tag)) + if ($tag->id_parent != 0) { if ($tag->kind === 'Album') { $buttons[] = [ - 'url' => BASEURL . '/uploadmedia/?tag=' . $id_tag, + 'url' => BASEURL . '/uploadmedia/?tag=' . $tag->id_tag, 'caption' => 'Upload photos here', ]; } @@ -157,14 +158,14 @@ class ViewPhotoAlbum extends HTMLController if ($tag->kind === 'Album') { $buttons[] = [ - 'url' => BASEURL . '/editalbum/?id=' . $id_tag, + 'url' => BASEURL . '/editalbum/?id=' . $tag->id_tag, 'caption' => 'Edit album', ]; } elseif ($tag->kind === 'Person') { $buttons[] = [ - 'url' => BASEURL . '/edittag/?id=' . $id_tag, + 'url' => BASEURL . '/edittag/?id=' . $tag->id_tag, 'caption' => 'Edit tag', ]; } @@ -174,7 +175,7 @@ class ViewPhotoAlbum extends HTMLController if ($user->isAdmin() && (!isset($tag) || $tag->kind === 'Album')) { $buttons[] = [ - 'url' => BASEURL . '/addalbum/?tag=' . $id_tag, + 'url' => BASEURL . '/addalbum/?tag=' . $tag->id_tag, 'caption' => 'Create subalbum', ]; } From 7cdcf8197cc53a26b369fe46f9071bdfa0fa8c19 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 14 Jan 2024 20:38:37 +0100 Subject: [PATCH 03/18] ViewPhotoAlbum: use Tag::getUrl instead of fumbling with $_GET['tag'] --- controllers/ViewPhotoAlbum.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index b74006f..5e99697 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -74,7 +74,7 @@ class ViewPhotoAlbum extends HTMLController 'recordCount' => $total_count, 'items_per_page' => self::PER_PAGE, 'start' => (isset($_GET['page']) ? $_GET['page'] - 1 : 0) * self::PER_PAGE, - 'base_url' => BASEURL . '/' . (isset($_GET['tag']) ? $_GET['tag'] . '/' : ''), + 'base_url' => $tag->getUrl(), 'page_slug' => 'page/%PAGE%/', 'index_class' => 'pagination-lg justify-content-around justify-content-lg-center', ]); @@ -82,8 +82,7 @@ class ViewPhotoAlbum extends HTMLController } // Set the canonical url. - $this->page->setCanonicalUrl(BASEURL . '/' . (isset($_GET['tag']) ? $_GET['tag'] . '/' : '') . - ($page > 1 ? 'page/' . $page . '/' : '')); + $this->page->setCanonicalUrl($tag->getUrl() . ($page > 1 ? 'page/' . $page . '/' : '')); } public function getPhotoMosaic($id_tag, $page, $sort_linear) From 16683d2f1fdeff7b3e5566aff94c2d4c65c0d2dd Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 14 Jan 2024 21:06:34 +0100 Subject: [PATCH 04/18] Tag: add getContributorList method --- models/Tag.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/models/Tag.php b/models/Tag.php index 14696f3..145db1e 100644 --- a/models/Tag.php +++ b/models/Tag.php @@ -141,6 +141,21 @@ class Tag 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') { $rows = Registry::get('db')->queryAssocs(' From 6a25ecec23dcd78992b3c9c493511b5a61c90e13 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 14 Jan 2024 21:06:54 +0100 Subject: [PATCH 05/18] ViewPhotoAlbum: add method to filter by id_user_uploaded --- controllers/ViewPhotoAlbum.php | 29 ++++++++++++++++++++++++++--- models/AssetIterator.php | 5 +++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index 5e99697..815f6d2 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -57,8 +57,30 @@ class ViewPhotoAlbum extends HTMLController $this->page->adopt($index); } + // Who contributed to this album? + $contributors = $tag->getContributorList(); + + // Enumerate possible filters + $filters = ['' => [null, 'Show all photos']]; + foreach ($contributors as $contributor) + { + $filters[$contributor['slug']] = [$contributor['id_user'], sprintf('%s %s (%s photos)', + $contributor['first_name'], $contributor['surname'], $contributor['num_assets'])]; + } + + // 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][0]; + } + // 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, $page, !isset($is_person)); if (isset($mosaic)) { $index = new PhotosIndex($mosaic, Registry::get('user')->isAdmin()); @@ -75,7 +97,7 @@ class ViewPhotoAlbum extends HTMLController 'items_per_page' => self::PER_PAGE, 'start' => (isset($_GET['page']) ? $_GET['page'] - 1 : 0) * self::PER_PAGE, 'base_url' => $tag->getUrl(), - 'page_slug' => 'page/%PAGE%/', + 'page_slug' => 'page/%PAGE%/' . (isset($active_filter) ? '?by=' . $active_filter : ''), 'index_class' => 'pagination-lg justify-content-around justify-content-lg-center', ]); $this->page->adopt(new PageIndexWidget($index)); @@ -85,11 +107,12 @@ class ViewPhotoAlbum extends HTMLController $this->page->setCanonicalUrl($tag->getUrl() . ($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. list($this->iterator, $total_count) = AssetIterator::getByOptions([ 'id_tag' => $id_tag, + 'id_user_uploaded' => $id_user_uploaded, 'order' => 'date_captured', 'direction' => $sort_linear ? 'asc' : 'desc', 'limit' => self::PER_PAGE, diff --git a/models/AssetIterator.php b/models/AssetIterator.php index 94132aa..2eabbf3 100644 --- a/models/AssetIterator.php +++ b/models/AssetIterator.php @@ -118,6 +118,11 @@ class AssetIterator extends Asset else $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'])) { $params['id_tag'] = $options['id_tag']; From 99b867b241b19ef6e3a45b85f6ff2b7137baf91e Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 14 Jan 2024 21:28:45 +0100 Subject: [PATCH 06/18] AlbumButtonBox: add way for users to select an album filter --- controllers/ViewPhotoAlbum.php | 53 +++++++++++++++++++--------------- public/css/default.css | 8 +++-- templates/AlbumButtonBox.php | 25 +++++++++++++++- 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index 815f6d2..0ff4129 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -37,50 +37,55 @@ class ViewPhotoAlbum extends HTMLController } // 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)) $this->page->adopt($header_box); - // Can we do fancy things here? - // !!! TODO: permission system? - $buttons = $this->getAlbumButtons($tag); - if (!empty($buttons)) - $this->page->adopt(new AlbumButtonBox($buttons)); - - // Fetch subalbums, but only if we're on the first page. - if ($page === 1) - { - $albums = $this->getAlbums($id_tag); - $index = new AlbumIndex($albums); - $this->page->adopt($index); - } - // Who contributed to this album? $contributors = $tag->getContributorList(); // Enumerate possible filters - $filters = ['' => [null, 'Show all photos']]; + $filters = ['' => ['id_user' => null, 'caption' => 'Show all photos', 'link' => $tag->getUrl()]]; foreach ($contributors as $contributor) { - $filters[$contributor['slug']] = [$contributor['id_user'], sprintf('%s %s (%s photos)', - $contributor['first_name'], $contributor['surname'], $contributor['num_assets'])]; + $filters[$contributor['slug']] = [ + 'id_user' => $contributor['id_user'], + '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; + $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][0]; + $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); + $button_strip = new AlbumButtonBox($buttons, $filters, $active_filter); + $this->page->adopt($button_strip); + + // Fetch subalbums, but only if we're on the first page. + if ($current_page === 1) + { + $albums = $this->getAlbums($id_tag); + $index = new AlbumIndex($albums); + $this->page->adopt($index); } // Load a photo mosaic for the current tag. - list($mosaic, $total_count) = $this->getPhotoMosaic($id_tag, $id_user_uploaded, $page, !isset($is_person)); + list($mosaic, $total_count) = $this->getPhotoMosaic($id_tag, $id_user_uploaded, $current_page, !isset($is_person)); if (isset($mosaic)) { $index = new PhotosIndex($mosaic, Registry::get('user')->isAdmin()); @@ -95,7 +100,7 @@ class ViewPhotoAlbum extends HTMLController $index = new PageIndex([ 'recordCount' => $total_count, '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' => $tag->getUrl(), 'page_slug' => 'page/%PAGE%/' . (isset($active_filter) ? '?by=' . $active_filter : ''), 'index_class' => 'pagination-lg justify-content-around justify-content-lg-center', @@ -104,7 +109,7 @@ class ViewPhotoAlbum extends HTMLController } // Set the canonical url. - $this->page->setCanonicalUrl($tag->getUrl() . ($page > 1 ? 'page/' . $page . '/' : '')); + $this->page->setCanonicalUrl($tag->getUrl() . ($current_page > 1 ? 'page/' . $current_page . '/' : '')); } public function getPhotoMosaic($id_tag, $id_user_uploaded, $page, $sort_linear) diff --git a/public/css/default.css b/public/css/default.css index 55f3581..ee3b117 100644 --- a/public/css/default.css +++ b/public/css/default.css @@ -339,9 +339,11 @@ div.polaroid a { ---------------------*/ .album_button_box { float: right; + display: flex; margin-bottom: 3rem; } -.album_button_box > a { +.album_button_box > a, +.album_button_box .btn { background: var(--bs-body-bg); box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); border-color: var( --bs-secondary-bg); @@ -349,7 +351,9 @@ div.polaroid a { padding: 8px 10px; 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); border-color: var(--bs-tertiary-bg); color: var(--bs-secondary-color); diff --git a/templates/AlbumButtonBox.php b/templates/AlbumButtonBox.php index 3956ffb..469fb34 100644 --- a/templates/AlbumButtonBox.php +++ b/templates/AlbumButtonBox.php @@ -8,11 +8,15 @@ class AlbumButtonBox extends Template { + private $active_filter; 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->filters = $filters; } public function html_main() @@ -25,6 +29,25 @@ class AlbumButtonBox extends Template ', $button['caption'], ''; echo ' + '; } } From 9c00248a7f0926c7d11cac2bab555b372f2237dd Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Sun, 14 Jan 2024 22:17:09 +0100 Subject: [PATCH 07/18] ViewPhotoAlbum: don't populate filter box if there are no album contributors --- controllers/ViewPhotoAlbum.php | 20 ++++++++++++-------- templates/AlbumButtonBox.php | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index 0ff4129..c15175e 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -47,15 +47,19 @@ class ViewPhotoAlbum extends HTMLController $contributors = $tag->getContributorList(); // Enumerate possible filters - $filters = ['' => ['id_user' => null, 'caption' => 'Show all photos', 'link' => $tag->getUrl()]]; - foreach ($contributors as $contributor) + $filters = []; + if (!empty($contributors)) { - $filters[$contributor['slug']] = [ - 'id_user' => $contributor['id_user'], - 'caption' => sprintf('By %s (%s photos)', - $contributor['first_name'], $contributor['num_assets']), - 'link' => $tag->getUrl() . '/?by=' . $contributor['slug'], - ]; + $filters[''] = ['id_user' => null, 'caption' => 'Show all photos', 'link' => $tag->getUrl()]; + foreach ($contributors as $contributor) + { + $filters[$contributor['slug']] = [ + 'id_user' => $contributor['id_user'], + 'caption' => sprintf('By %s (%s photos)', + $contributor['first_name'], $contributor['num_assets']), + 'link' => $tag->getUrl() . '/?by=' . $contributor['slug'], + ]; + } } // Limit to a particular uploader? diff --git a/templates/AlbumButtonBox.php b/templates/AlbumButtonBox.php index 469fb34..ea631ea 100644 --- a/templates/AlbumButtonBox.php +++ b/templates/AlbumButtonBox.php @@ -28,26 +28,31 @@ class AlbumButtonBox extends Template echo ' ', $button['caption'], ''; - echo ' + if (!empty($this->filters)) + { + echo ' '; } echo ' - - '; } } From f33a7e397cb2495e0c9957484df3bee9730c39f2 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Mon, 15 Jan 2024 00:19:39 +0100 Subject: [PATCH 08/18] Asset: combine getUrlFor{Next,Previous}InSet into one private method --- models/Asset.php | 86 ++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/models/Asset.php b/models/Asset.php index 3fc9d04..45f8c1b 100644 --- a/models/Asset.php +++ b/models/Asset.php @@ -697,27 +697,48 @@ class Asset $params); } - public function getUrlForPreviousInSet(?Tag $tag) + protected function getUrlForAdjacentInSet($prevNext, ?Tag $tag) { + $next = $prevNext === 'next'; + $previous = !$next; + + $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)) + { + $where[] = 't.id_tag = {int:id_tag}'; + $params['id_tag'] = $tag->id_tag; + $params['where_op'] = $previous ? '<' : '>'; + $params['order_dir'] = $previous ? 'DESC' : 'ASC'; + } + else + { + $params['where_op'] = $previous ? '>' : '<'; + $params['order_dir'] = $previous ? 'ASC' : 'DESC'; + } + + // 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.* - ' . (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') - . ' + ' . (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', - [ - 'id_asset' => $this->id_asset, - 'id_tag' => isset($tag) ? $tag->id_tag : null, - 'date_captured' => $this->date_captured, - ]); + $params); if ($row) { @@ -728,34 +749,13 @@ class Asset return false; } + public function getUrlForPreviousInSet(?Tag $tag) + { + return $this->getUrlForAdjacentInSet('previous', $tag); + } + public function getUrlForNextInSet(?Tag $tag) { - $row = Registry::get('db')->queryAssoc(' - 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) - { - $obj = self::byRow($row, 'object'); - return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : ''); - } - else - return false; + return $this->getUrlForAdjacentInSet('next', $tag); } } From d8c3e76df6cde8c4fdde35a2f9f7cfb22dc5cd67 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Mon, 15 Jan 2024 00:43:02 +0100 Subject: [PATCH 09/18] ViewPhoto: take filter into account for prev/next links --- controllers/ViewPhoto.php | 13 ++++++++++++ controllers/ViewPhotoAlbum.php | 11 ++++++++-- models/Asset.php | 37 ++++++++++++++++++++++++---------- templates/PhotoPage.php | 10 +++++++-- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/controllers/ViewPhoto.php b/controllers/ViewPhoto.php index ab53c0f..fb151a0 100644 --- a/controllers/ViewPhoto.php +++ b/controllers/ViewPhoto.php @@ -46,6 +46,19 @@ class ViewPhoto extends HTMLController if (isset($tag)) $page->setTag($tag); + // Keeping tabs on a filter? + if (isset($_GET['by'])) + { + // Let's first verify that the filter is valid + $contributors = array_filter($tag->getContributorList(), fn($el) => $el['slug'] === $_GET['by']); + if (count($contributors) !== 1) + throw new UnexpectedValueException('Invalid filter for this album or tag.'); + + // Alright, let's run with it then + $filter = reset($contributors); + $page->setActiveFilter($filter['slug']); + } + $this->page->adopt($page); $this->page->setCanonicalUrl($this->photo->getPageUrl()); } diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index c15175e..55c72b7 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -94,8 +94,15 @@ class ViewPhotoAlbum extends HTMLController { $index = new PhotosIndex($mosaic, Registry::get('user')->isAdmin()); $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. diff --git a/models/Asset.php b/models/Asset.php index 45f8c1b..9510735 100644 --- a/models/Asset.php +++ b/models/Asset.php @@ -697,7 +697,7 @@ class Asset $params); } - protected function getUrlForAdjacentInSet($prevNext, ?Tag $tag) + protected function getUrlForAdjacentInSet($prevNext, ?Tag $tag, $activeFilter) { $next = $prevNext === 'next'; $previous = !$next; @@ -722,6 +722,14 @@ class Asset $params['order_dir'] = $previous ? 'ASC' : 'DESC'; } + // Take active filter into account as well + if (!empty($activeFilter)) + { + $user = Member::fromSlug($activeFilter); + $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})'; @@ -740,22 +748,29 @@ class Asset LIMIT 1', $params); - if ($row) - { - $obj = self::byRow($row, 'object'); - return $obj->getPageUrl() . ($tag ? '?in=' . $tag->id_tag : ''); - } - else + if (!$row) 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 getUrlForPreviousInSet(?Tag $tag) + public function getUrlForPreviousInSet(?Tag $tag, $activeFilter) { - return $this->getUrlForAdjacentInSet('previous', $tag); + return $this->getUrlForAdjacentInSet('previous', $tag, $activeFilter); } - public function getUrlForNextInSet(?Tag $tag) + public function getUrlForNextInSet(?Tag $tag, $activeFilter) { - return $this->getUrlForAdjacentInSet('next', $tag); + return $this->getUrlForAdjacentInSet('next', $tag, $activeFilter); } } diff --git a/templates/PhotoPage.php b/templates/PhotoPage.php index b74e420..0b30954 100644 --- a/templates/PhotoPage.php +++ b/templates/PhotoPage.php @@ -8,6 +8,7 @@ class PhotoPage extends Template { + private $activeFilter; private $photo; private $metaData; private $tag; @@ -78,6 +79,11 @@ class PhotoPage extends Template '; } + public function setActiveFilter($filter) + { + $this->activeFilter = $filter; + } + public function setTag(Tag $tag) { $this->tag = $tag; @@ -85,14 +91,14 @@ class PhotoPage extends Template private function photoNav() { - if ($previousUrl = $this->photo->getUrlForPreviousInSet($this->tag)) + if ($previousUrl = $this->photo->getUrlForPreviousInSet($this->tag, $this->activeFilter)) echo ' '; else echo ' '; - if ($nextUrl = $this->photo->getUrlForNextInSet($this->tag)) + if ($nextUrl = $this->photo->getUrlForNextInSet($this->tag, $this->activeFilter)) echo ' '; else From accf09393506b66050329dd020f8349488023844 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Mon, 15 Jan 2024 00:51:06 +0100 Subject: [PATCH 10/18] PageIndex: rewrite getLink to be way less messy --- models/PageIndex.php | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/models/PageIndex.php b/models/PageIndex.php index 0c988cc..b120681 100644 --- a/models/PageIndex.php +++ b/models/PageIndex.php @@ -155,24 +155,20 @@ class PageIndex public function getLink($start = null, $order = null, $dir = null) { - $url = $this->base_url; - $amp = strpos($this->base_url, '?') ? '&' : '?'; + $page = !is_string($start) ? ($start / $this->items_per_page) + 1 : $start; + $url = $this->base_url . str_replace('%PAGE%', $page, $this->page_slug); - if (!empty($start)) - { - $page = $start !== '%d' ? ($start / $this->items_per_page) + 1 : $start; - $url .= strtr($this->page_slug, ['%PAGE%' => $page, '%AMP%' => $amp]); - $amp = '&'; - } + $urlParams = []; if (!empty($order)) - { - $url .= $amp . 'order=' . $order; - $amp = '&'; - } + $urlParams['order'] = $order; if (!empty($dir)) + $urlParams['dir'] = $dir; + + if (!empty($urlParams)) { - $url .= $amp . 'dir=' . $dir; - $amp = '&'; + $queryString = (strpos($uri, '?') !== false ? '&' : '?'); + $queryString .= http_build_query($urlParams); + $url .= $queryString; } return $url; From 1f53689e4bbdb795ca32eefe1d770bb406485b46 Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Mon, 15 Jan 2024 00:55:33 +0100 Subject: [PATCH 11/18] AlbumButtonBox: add visual cue to indicate a filter is active --- controllers/ViewPhotoAlbum.php | 1 + templates/AlbumButtonBox.php | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/controllers/ViewPhotoAlbum.php b/controllers/ViewPhotoAlbum.php index 55c72b7..f4e7f77 100644 --- a/controllers/ViewPhotoAlbum.php +++ b/controllers/ViewPhotoAlbum.php @@ -55,6 +55,7 @@ class ViewPhotoAlbum extends HTMLController { $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'], diff --git a/templates/AlbumButtonBox.php b/templates/AlbumButtonBox.php index ea631ea..7626fa3 100644 --- a/templates/AlbumButtonBox.php +++ b/templates/AlbumButtonBox.php @@ -33,7 +33,16 @@ class AlbumButtonBox extends Template echo '