mirror of
https://github.com/standardebooks/web.git
synced 2025-07-08 15:50:29 -04:00
Allow admin to view collection metadata
This commit is contained in:
parent
bcc2f331bc
commit
23b5c8ef31
8 changed files with 82 additions and 55 deletions
|
@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS `Benefits` (
|
||||||
`CanReviewArtwork` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
`CanReviewArtwork` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
`CanReviewOwnArtwork` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
`CanReviewOwnArtwork` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
`CanEditUsers` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
`CanEditUsers` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`CanEditCollections` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
`CanCreateEbookPlaceholders` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
`CanCreateEbookPlaceholders` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
PRIMARY KEY (`UserId`),
|
PRIMARY KEY (`UserId`),
|
||||||
KEY `idxBenefits` (`CanAccessFeeds`,`CanVote`,`CanBulkDownload`)
|
KEY `idxBenefits` (`CanAccessFeeds`,`CanVote`,`CanBulkDownload`)
|
||||||
|
|
|
@ -15,6 +15,7 @@ class Benefits{
|
||||||
public bool $CanReviewArtwork = false;
|
public bool $CanReviewArtwork = false;
|
||||||
public bool $CanReviewOwnArtwork = false;
|
public bool $CanReviewOwnArtwork = false;
|
||||||
public bool $CanEditUsers = false;
|
public bool $CanEditUsers = false;
|
||||||
|
public bool $CanEditCollections = false;
|
||||||
public bool $CanCreateEbookPlaceholders = false;
|
public bool $CanCreateEbookPlaceholders = false;
|
||||||
|
|
||||||
protected bool $_HasBenefits;
|
protected bool $_HasBenefits;
|
||||||
|
|
|
@ -3,6 +3,7 @@ use function Safe\preg_replace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property string $Url
|
* @property string $Url
|
||||||
|
* @property array<Ebook> $Ebooks
|
||||||
*/
|
*/
|
||||||
class Collection{
|
class Collection{
|
||||||
use Traits\Accessor;
|
use Traits\Accessor;
|
||||||
|
@ -13,7 +14,9 @@ class Collection{
|
||||||
public ?Enums\CollectionType $Type = null;
|
public ?Enums\CollectionType $Type = null;
|
||||||
public bool $ArePlaceholdersComplete; /** Has a producer verified that every possible item in this `Collection` been added to our database? */
|
public bool $ArePlaceholdersComplete; /** Has a producer verified that every possible item in this `Collection` been added to our database? */
|
||||||
|
|
||||||
protected ?string $_Url = null;
|
protected string $_Url;
|
||||||
|
/** @var array<Ebook> $_Ebooks */
|
||||||
|
protected array $_Ebooks;
|
||||||
|
|
||||||
|
|
||||||
// *******
|
// *******
|
||||||
|
@ -21,13 +24,24 @@ class Collection{
|
||||||
// *******
|
// *******
|
||||||
|
|
||||||
protected function GetUrl(): string{
|
protected function GetUrl(): string{
|
||||||
if($this->_Url === null){
|
if(!isset($this->_Url)){
|
||||||
$this->_Url = '/collections/' . $this->UrlName;
|
$this->_Url = '/collections/' . $this->UrlName;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->_Url;
|
return $this->_Url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<Ebook>
|
||||||
|
*/
|
||||||
|
protected function GetEbooks(): array{
|
||||||
|
if(!isset($this->_Ebooks)){
|
||||||
|
$this->_Ebooks = Ebook::GetAllByCollection($this->CollectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_Ebooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ***********
|
// ***********
|
||||||
// ORM METHODS
|
// ORM METHODS
|
||||||
|
@ -57,6 +71,23 @@ class Collection{
|
||||||
return $result[0] ?? throw new Exceptions\CollectionNotFoundException();;
|
return $result[0] ?? throw new Exceptions\CollectionNotFoundException();;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\CollectionNotFoundException
|
||||||
|
*/
|
||||||
|
public static function GetByUrlName(?string $urlName): Collection{
|
||||||
|
if($urlName === null){
|
||||||
|
throw new Exceptions\CollectionNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Db::Query('
|
||||||
|
SELECT *
|
||||||
|
from Collections
|
||||||
|
where UrlName = ?
|
||||||
|
', [$urlName], Collection::class);
|
||||||
|
|
||||||
|
return $result[0] ?? throw new Exceptions\CollectionNotFoundException();;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<Collection>
|
* @return array<Collection>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2020,17 +2020,17 @@ class Ebook{
|
||||||
* Queries for books in a collection.
|
* Queries for books in a collection.
|
||||||
*
|
*
|
||||||
* Puts ebooks without a `SequenceNumber` at the end of the list, which is more common in a collection with both published and placeholder ebooks.
|
* Puts ebooks without a `SequenceNumber` at the end of the list, which is more common in a collection with both published and placeholder ebooks.
|
||||||
|
*
|
||||||
* @return array<Ebook>
|
* @return array<Ebook>
|
||||||
*/
|
*/
|
||||||
public static function GetAllByCollection(string $collection): array{
|
public static function GetAllByCollection(int $collectionId): array{
|
||||||
$ebooks = Db::Query('
|
$ebooks = Db::Query('
|
||||||
SELECT e.*
|
SELECT e.*
|
||||||
from Ebooks e
|
from Ebooks e
|
||||||
inner join CollectionEbooks ce using (EbookId)
|
inner join CollectionEbooks ce using (EbookId)
|
||||||
inner join Collections c using (CollectionId)
|
where ce.CollectionId = ?
|
||||||
where c.UrlName = ?
|
|
||||||
order by ce.SequenceNumber is null, ce.SequenceNumber, e.EbookCreated desc
|
order by ce.SequenceNumber is null, ce.SequenceNumber, e.EbookCreated desc
|
||||||
', [$collection], Ebook::class);
|
', [$collectionId], Ebook::class);
|
||||||
|
|
||||||
return $ebooks;
|
return $ebooks;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,34 +2,15 @@
|
||||||
use function Safe\preg_replace;
|
use function Safe\preg_replace;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$collection = HttpInput::Str(GET, 'collection') ?? '';
|
$collection = Collection::GetByUrlName(HttpInput::Str(GET, 'collection'));
|
||||||
$collectionObject = null;
|
$collectionName = preg_replace('/^The /ius', '', $collection->Name);
|
||||||
$collectionName = '';
|
$collectionType = $collection->Type->value ?? 'collection';
|
||||||
$collectionType = '';
|
|
||||||
|
|
||||||
$ebooks = Ebook::GetAllByCollection($collection);
|
|
||||||
// Get the *actual* name of the collection, in case there are accent marks (like `Arsène Lupin`).
|
|
||||||
if(sizeof($ebooks) > 0){
|
|
||||||
foreach($ebooks[0]->CollectionMemberships as $cm){
|
|
||||||
$c = $cm->Collection;
|
|
||||||
if($collection == Formatter::MakeUrlSafe($c->Name)){
|
|
||||||
$collectionObject = $c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($collectionObject === null){
|
|
||||||
throw new Exceptions\CollectionNotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
$collectionName = preg_replace('/^The /ius', '', $collectionObject->Name);
|
|
||||||
$collectionType = $collectionObject->Type->value ?? 'collection';
|
|
||||||
|
|
||||||
$pageTitle = 'Browse free ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
$pageTitle = 'Browse free ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
||||||
$pageDescription = 'A list of free ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
$pageDescription = 'A list of free ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
||||||
$pageHeader = 'Free Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . ucfirst($collectionType);
|
$pageHeader = 'Free Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . ucfirst($collectionType);
|
||||||
|
|
||||||
$feedUrl = '/collections/' . $collection;
|
$feedUrl = '/collections/' . $collection->UrlName;
|
||||||
$feedTitle = 'Standard Ebooks - Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
$feedTitle = 'Standard Ebooks - Ebooks in the ' . Formatter::EscapeHtml($collectionName) . ' ' . $collectionType;
|
||||||
}
|
}
|
||||||
catch(Exceptions\CollectionNotFoundException){
|
catch(Exceptions\CollectionNotFoundException){
|
||||||
|
@ -44,13 +25,26 @@ catch(Exceptions\CollectionNotFoundException){
|
||||||
<?= Template::DonationAlert() ?>
|
<?= Template::DonationAlert() ?>
|
||||||
|
|
||||||
<p class="ebooks-toolbar">
|
<p class="ebooks-toolbar">
|
||||||
<a class="button" href="/collections/<?= Formatter::EscapeHtml($collection) ?>/downloads">Download collection</a>
|
<a class="button" href="/collections/<?= Formatter::EscapeHtml($collection->UrlName) ?>/downloads">Download collection</a>
|
||||||
<a class="button" href="/collections/<?= Formatter::EscapeHtml($collection) ?>/feeds">Collection feeds</a>
|
<a class="button" href="/collections/<?= Formatter::EscapeHtml($collection->UrlName) ?>/feeds">Collection feeds</a>
|
||||||
</p>
|
</p>
|
||||||
<? if(sizeof($ebooks) == 0){ ?>
|
|
||||||
|
<? if(sizeof($collection->Ebooks) == 0){ ?>
|
||||||
<p class="no-results">No ebooks matched your filters. You can try different filters, or <a href="/ebooks">browse all of our ebooks</a>.</p>
|
<p class="no-results">No ebooks matched your filters. You can try different filters, or <a href="/ebooks">browse all of our ebooks</a>.</p>
|
||||||
<? }else{ ?>
|
<? }else{ ?>
|
||||||
<?= Template::EbookGrid(['ebooks' => $ebooks, 'view' => Enums\ViewType::Grid, 'collection' => $collectionObject]) ?>
|
<?= Template::EbookGrid(['ebooks' => $collection->Ebooks, 'view' => Enums\ViewType::Grid, 'collection' => $collection]) ?>
|
||||||
|
<? } ?>
|
||||||
|
|
||||||
|
<? if(Session::$User?->Benefits->CanEditCollections){ ?>
|
||||||
|
<h2>Metadata</h2>
|
||||||
|
<table class="admin-table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Collection ID:</td>
|
||||||
|
<td><?= $collection->CollectionId ?></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<p class="feeds-alert">We also have <a href="/bulk-downloads">bulk ebook downloads</a> and a <a href="/collections">list of collections</a> available, as well as <a href="/feeds">ebook catalog feeds</a> for use directly in your ereader app or RSS reader.</p>
|
<p class="feeds-alert">We also have <a href="/bulk-downloads">bulk ebook downloads</a> and a <a href="/collections">list of collections</a> available, as well as <a href="/feeds">ebook catalog feeds</a> for use directly in your ereader app or RSS reader.</p>
|
||||||
|
|
|
@ -3254,6 +3254,25 @@ ol.ebooks-list > li.ribbon.not-pd a::after{
|
||||||
content: "not p.d. yet";
|
content: "not p.d. yet";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2 + table.admin-table{
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.admin-table td{
|
||||||
|
padding: .5rem;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.admin-table td:first-child{
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.admin-table td + td{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: none) and (pointer: coarse){ /* target ipads and smartphones without a mouse */
|
@media (hover: none) and (pointer: coarse){ /* target ipads and smartphones without a mouse */
|
||||||
/* For iPad, unset the height so it matches the other elements */
|
/* For iPad, unset the height so it matches the other elements */
|
||||||
select[multiple]{
|
select[multiple]{
|
||||||
|
|
|
@ -7,25 +7,6 @@ label:has(input[name="password-action"]) + label{
|
||||||
margin-top: .5rem;
|
margin-top: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 + table{
|
|
||||||
margin-top: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
table td{
|
|
||||||
padding: .5rem;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
table td:first-child{
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: right;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
table td + td{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
form{
|
form{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -52,7 +52,7 @@ catch(Exceptions\SeeOtherException $ex){
|
||||||
<a href="<?= $user->Url ?>/edit">Edit user</a>
|
<a href="<?= $user->Url ?>/edit">Edit user</a>
|
||||||
|
|
||||||
<h2>Basics</h2>
|
<h2>Basics</h2>
|
||||||
<table>
|
<table class="admin-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Email:</td>
|
<td>Email:</td>
|
||||||
|
@ -74,7 +74,7 @@ catch(Exceptions\SeeOtherException $ex){
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h2>Patron info</h2>
|
<h2>Patron info</h2>
|
||||||
<table>
|
<table class="admin-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Is Patron:</td>
|
<td>Is Patron:</td>
|
||||||
|
@ -134,7 +134,7 @@ catch(Exceptions\SeeOtherException $ex){
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<h2>Registration info</h2>
|
<h2>Registration info</h2>
|
||||||
<table>
|
<table class="admin-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Is registered:</td>
|
<td>Is registered:</td>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue