Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable default cover images #4061

Merged
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
89367b2
disable default cover images
ThoWagen Nov 6, 2024
2303baa
updated comments
ThoWagen Nov 6, 2024
68ecd79
renamed exception
ThoWagen Nov 7, 2024
ac168ee
fixed doc comment
ThoWagen Nov 7, 2024
7bc40ce
added comment in configs
ThoWagen Nov 8, 2024
adc7567
updated comment and added testcase for deactivated setting
ThoWagen Nov 8, 2024
e9a72f0
Merge branch 'dev' into pull-request/disable-default-cover-images
demiankatz Nov 11, 2024
9cdb407
added demo cover loader
ThoWagen Nov 12, 2024
f547606
readded default no qr code availabe image
ThoWagen Nov 12, 2024
c02ae99
Add DemoAjax.
demiankatz Nov 12, 2024
258fba0
Merge branch 'add-demo-covers' into pull-request/disable-default-cove…
demiankatz Nov 12, 2024
162947f
Add DemoAjax version.
demiankatz Nov 12, 2024
06650fe
Revise comment.
demiankatz Nov 12, 2024
2000215
combined demo and demoajax and hiding one pixel image as default inst…
ThoWagen Nov 13, 2024
9acfcc9
added hidden-image.gif
ThoWagen Nov 13, 2024
c99f342
Fix comment formatting.
demiankatz Nov 13, 2024
d06e002
Fix return type.
demiankatz Nov 13, 2024
4c3598f
Merge remote-tracking branch 'origin/dev' into pull-request/disable-d…
demiankatz Nov 13, 2024
826806a
Favor record ID for more consistent generation.
demiankatz Nov 13, 2024
21d94dd
Add Mink test.
demiankatz Nov 13, 2024
1c48f06
disable cover image cache in browsers for tests and wait for complete…
ThoWagen Nov 22, 2024
d51c09e
Merge branch 'dev' into pull-request/disable-default-cover-images
ThoWagen Nov 22, 2024
f37deb8
fixed cs and tests
ThoWagen Nov 22, 2024
8dce3d1
using VuFind.setInnerHtml
ThoWagen Nov 22, 2024
02d7117
using array instead of laminas config
ThoWagen Nov 25, 2024
3c9070e
Update module/VuFind/src/VuFind/Cover/RouterFactory.php
demiankatz Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions config/vufind/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1066,8 +1066,8 @@ verify_server_certificate = false
;coversize = false

; You can select Syndetics, LibraryThing, Summon, Booksite, OpenLibrary,
; Contentcafe, Buchhandel.de, Google, BrowZine, ObalkyKnih, Orb, Koha and/or
; LocalFile. Service-specific notes:
; Contentcafe, Buchhandel.de, Google, BrowZine, ObalkyKnih, Orb, Koha, Demo,
; and/or LocalFile. Service-specific notes:
; - BrowZine requires you to have BrowZine.ini configured appropriately.
; - Google Books caching behavior can be customized in the [Cache_GoogleCover]
; section.
Expand All @@ -1076,6 +1076,10 @@ verify_server_certificate = false
; OPACLocalCoverImages system preferences must be turned on and local cover
; images uploaded to the Koha system. Koha emits only two sizes of cover
; images, so small and medium are treated the same in VuFind.
; - Demo should only be used for testing. It will return an image with filename
; "demo-cover-*" from the themes or no image. This is evenly distributed based on
; the checksum of the record's parameters like id, isbn etc. Use Demo:true to activate
; backlink functionality when ajaxcovers are active.
; - LocalFile:PathToFile supports a combination of directory path information
; and tokens for filename and image type. If you have multiple directories
; in which you have stored coverimages, you can specify multiple paths to search
Expand Down Expand Up @@ -1113,6 +1117,9 @@ verify_server_certificate = false
; some services will never have images cached even if caching is enabled.
coverimagesCache = true

; This setting controls if browsers will cache cover images. This is mainly intended for testing purposes.
;coverimagesBrowserCache = true

; This setting controls which proxied image URLs will be cached to local disk (when
; using the ?proxy= parameter of the standard /Cover/Show routes). The setting may
; contain one or more regular expressions matching hostnames. The example
Expand Down Expand Up @@ -1155,6 +1162,7 @@ coverproxyAllowedTypes[] = "image/png"

; Otherwise, you can use noCoverAvailableImage to specify a
; path relative to the base of your theme directory for a static image to display.
; If set to "false", no image will be displayed for unavailable covers.
noCoverAvailableImage = images/noCover2.gif

; You can select from Syndetics, SyndeticsPlus, Booksite and/or the Guardian
Expand Down Expand Up @@ -1317,7 +1325,8 @@ url = "https://api.vlb.de/api/v1/cover/"

[QRCode]
; This setting controls the image to display when no qrcode is available.
; The path is relative to the base of your theme directory.
; The path is relative to the base of your theme directory. Default is
; "images/noQRCode.gif".
;noQRCodeAvailableImage = images/noQRCode.gif

; Should we show QR codes in search results?
Expand Down
138 changes: 138 additions & 0 deletions module/VuFind/src/VuFind/Content/Covers/Demo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

/**
* Demo cover content loader.
*
* PHP version 8
*
* Copyright (C) Hebis Verbundzentrale 2024.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category VuFind
* @package Content
* @author Thomas Wagener <[email protected]>
* @author Demian Katz <[email protected]>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/

namespace VuFind\Content\Covers;

use VuFindTheme\ThemeInfo;

use function count;

/**
* Demo cover content loader.
*
* @category VuFind
* @package Content
* @author Thomas Wagener <[email protected]>
* @author Demian Katz <[email protected]>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development Wiki
*/
class Demo extends \VuFind\Content\AbstractCover
{
/**
* Constructor
*
* @param ThemeInfo $themeInfo Theme info
* @param string $baseUrl VuFind's base URL
*/
public function __construct(protected ThemeInfo $themeInfo, protected string $baseUrl)
{
$this->directUrls = true;
$this->mandatoryBacklinkLocations = ['core'];
}

/**
* Does this plugin support the provided ID array?
*
* @param array $ids IDs that will later be sent to load() -- see below.
*
* @return bool
*/
public function supports($ids)
{
// We won't know what we need until we parse the path string; accept
// everything at this stage:
return true;
}

/**
* Get image location from local file storage.
*
* @param string $key If backlink functionality should be used
* @param string $size Size of image to load (small/medium/large)
* @param array $ids Associative array of identifiers (keys may include 'isbn'
* pointing to an ISBN object and 'issn' pointing to a string)
*
* @return string|bool
*/
public function getUrl($key, $size, $ids)
{
$cover = $this->getCover($ids);
if ($path = $cover['file'] ?? null) {
return 'file://' . $path;
}
return false;
}

/**
* Get cover metadata for a particular API key and set of IDs (or empty array).
*
* @param ?string $key If backlink functionality should be used
* @param string $size Size of image to load (small/medium/large)
* @param array $ids Associative array of identifiers (keys may include 'isbn'
* pointing to an ISBN object, 'issn' pointing to a string and 'oclc' pointing
* to an OCLC number string)
*
* @return array Array with keys: url, backlink_url, backlink_text
*/
public function getMetadata(?string $key, string $size, array $ids)
{
$cover = $this->getCover($ids);
$path = $cover['relativeFile'] ?? null;
if (empty($path)) {
return [];
}
$res = [
'url' => $this->baseUrl . 'themes/' . $cover['theme'] . '/' . $path,
];
if ($key === 'true') {
$res['backlink_url'] = 'https://vufind.org';
$res['backlink_text'] = 'vufind.org';
}
return $res;
}

/**
* Selects demo covers or no cover based on the $ids array and returns location information.
*
* @param array $ids Associative array of identifiers (keys may include 'isbn'
* pointing to an ISBN object and 'issn' pointing to a string)
*
* @return array
*/
protected function getCover($ids)
{
$covers = $this->themeInfo->findInThemes('images/demo-cover-*');
// selects either one of the available demo covers or no image
// evenly distributed based on the checksum of the ids.
$coverNum = crc32($ids['recordid'] ?? serialize($ids)) % (count($covers) + 1);
return $covers[$coverNum] ?? [];
}
}
77 changes: 77 additions & 0 deletions module/VuFind/src/VuFind/Content/Covers/DemoFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

/**
* Demo cover loader factory
*
* PHP version 8
*
* Copyright (C) Hebis Verbundzentrale 2024.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category VuFind
* @package Content
* @author Thomas Wagener <[email protected]>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development:plugins:record_drivers Wiki
*/

namespace VuFind\Content\Covers;

use Laminas\ServiceManager\Exception\ServiceNotCreatedException;
use Laminas\ServiceManager\Exception\ServiceNotFoundException;
use Psr\Container\ContainerExceptionInterface as ContainerException;
use Psr\Container\ContainerInterface;

/**
* Demo cover loader factory
*
* @category VuFind
* @package Content
* @author Thomas Wagener <[email protected]>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org/wiki/development:plugins:record_drivers Wiki
*/
class DemoFactory implements \Laminas\ServiceManager\Factory\FactoryInterface
{
/**
* Create an object
*
* @param ContainerInterface $container Service manager
* @param string $requestedName Service being created
* @param null|array $options Extra options (optional)
*
* @return object
*
* @throws ServiceNotFoundException if unable to resolve the service.
* @throws ServiceNotCreatedException if an exception is raised when
* creating a service.
* @throws ContainerException&\Throwable if any other error occurs
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function __invoke(
ContainerInterface $container,
$requestedName,
array $options = null
) {
if (!empty($options)) {
throw new \Exception('Unexpected options passed to factory.');
}
$helpers = $container->get('ViewHelperManager');
$basePath = ($helpers->get('url'))('home');
$baseUrl = ($helpers->get('serverurl'))($basePath);
return new $requestedName($container->get(\VuFindTheme\ThemeInfo::class), $baseUrl);
}
}
2 changes: 2 additions & 0 deletions module/VuFind/src/VuFind/Content/Covers/PluginManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
'buchhandel' => Buchhandel::class,
'browzine' => BrowZine::class,
'contentcafe' => ContentCafe::class,
'demo' => Demo::class,
'google' => Google::class,
'koha' => Koha::class,
'librarything' => LibraryThing::class,
Expand All @@ -79,6 +80,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
BrowZine::class => BrowZineFactory::class,
Buchhandel::class => BuchhandelFactory::class,
ContentCafe::class => ContentCafeFactory::class,
Demo::class => DemoFactory::class,
Deprecated::class => InvokableFactory::class,
Google::class => GoogleFactory::class,
Koha::class => KohaFactory::class,
Expand Down
42 changes: 28 additions & 14 deletions module/VuFind/src/VuFind/Controller/CoverController.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,34 @@ protected function displayImage($type = null, $image = null)
// Send proper caching headers so that the user's browser
// is able to cache the cover images and not have to re-request
// then on each page load. Default TTL set at 14 days

$coverImageTtl = (60 * 60 * 24 * 14); // 14 days
$headers->addHeaderLine(
'Cache-Control',
'maxage=' . $coverImageTtl
);
$headers->addHeaderLine(
'Pragma',
'public'
);
$headers->addHeaderLine(
'Expires',
gmdate('D, d M Y H:i:s', time() + $coverImageTtl) . ' GMT'
);
if ($this->config['coverimagesBrowserCache'] ?? true) {
$coverImageTtl = (60 * 60 * 24 * 14); // 14 days
$headers->addHeaderLine(
'Cache-Control',
'maxage=' . $coverImageTtl
);
$headers->addHeaderLine(
'Pragma',
'public'
);
$headers->addHeaderLine(
'Expires',
gmdate('D, d M Y H:i:s', time() + $coverImageTtl) . ' GMT'
);
} else {
$headers->addHeaderLine(
'Cache-Control',
'no-cache, no-store, must-revalidate'
);
$headers->addHeaderLine(
'Pragma',
'no-cache'
);
$headers->addHeaderLine(
'Expires',
'0'
);
}

$response->setContent($image ?: $this->loader->getImage());
return $response;
Expand Down
32 changes: 13 additions & 19 deletions module/VuFind/src/VuFind/Cover/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

namespace VuFind\Cover;

use Laminas\Config\Config;
use VuFind\Cover\Loader as CoverLoader;
use VuFind\RecordDriver\AbstractBase as RecordDriver;

Expand All @@ -48,30 +49,18 @@ class Router implements \Laminas\Log\LoggerAwareInterface
{
use \VuFind\Log\LoggerAwareTrait;

/**
* Base URL for dynamic cover images.
*
* @var string
*/
protected $dynamicUrl;

/**
* Cover loader
*
* @var CoverLoader
*/
protected $coverLoader;

/**
* Constructor
*
* @param string $url Base URL for dynamic cover images.
* @param string $dynamicUrl Base URL for dynamic cover images.
* @param CoverLoader $coverLoader Cover loader
* @param Config $config Content config
*/
public function __construct($url, CoverLoader $coverLoader)
{
$this->dynamicUrl = $url;
$this->coverLoader = $coverLoader;
public function __construct(
protected string $dynamicUrl,
protected CoverLoader $coverLoader,
protected Config $config
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

laminas-config has just been abandoned; I'm beginning work to remove it from the project. I'd suggest using a plain array here, and using ->toArray in the factory, so we don't introduce a new dependency on the abandoned project.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also make sense to default this to an empty array so that you don't have to modify tests when there is no configuration being tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Are there any problems with replacing laminas-config with arrays that would be good to keep in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My plan is to create a VuFind\Config\Config that provides backward-compatibility with Laminas\Config\Config as a first phase. We might decide to keep that in the long term, but I think it's more likely that we'll quickly deprecate it and try to phase it out in favor of arrays. Really, the Laminas Config object was mainly useful for accessing deep configs in older versions of PHP prior to the introduction of null coalescing. Now that we have ??, it's pretty easy to access deeply-nested array properties as long as you provide a default to fall back on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks

) {
}

/**
Expand Down Expand Up @@ -137,6 +126,11 @@ public function getMetadata(
return false;
}

if (!($this->config->coverimagesBrowserCache ?? true)) {
// Add timestamp hash to avoid browser cache
$thumb['hash'] = md5(time());
}

// Array? It's parameters to send to the cover generator:
if (is_array($thumb)) {
if (!$resolveDynamic) {
Expand Down
3 changes: 2 additions & 1 deletion module/VuFind/src/VuFind/Cover/RouterFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public function __invoke(
$base = ($container->get('ViewRenderer')->plugin('url'))('cover-show');
}
$coverLoader = $container->get(\VuFind\Cover\Loader::class);
return new $requestedName($base, $coverLoader);
$config = $container->get(\VuFind\Config\PluginManager::class)->get('config')->Content;
return new $requestedName($base, $coverLoader, $config);
}
}
Loading
Loading