Allow creating new ebook placeholders when creating a new project

This commit is contained in:
Alex Cabal 2024-12-18 22:23:39 -06:00
parent 4596aeb007
commit 98e09f414e
14 changed files with 114 additions and 44 deletions

View file

@ -0,0 +1,7 @@
<?
namespace Exceptions;
class InvalidDiscussionUrlException extends InvalidUrlException{
/** @var string $message */
protected $message = 'Invalid discussion URL.';
}

View file

@ -222,6 +222,10 @@ final class Project{
// Get the base thread URL in case we were passed a URL with a specific message or query string.
$this->DiscussionUrl = preg_replace('|^(https://groups\.google\.com/g/standardebooks/c/[^/]+).*|iu', '\1', $this->DiscussionUrl);
}
if(!preg_match('|^https://groups\.google\.com/g/standardebooks/c/[^/\?]+$|iu', $this->DiscussionUrl)){
$error->Add(new Exceptions\InvalidDiscussionUrlException($this->DiscussionUrl));
}
}
$this->VcsUrl = trim($this->VcsUrl ?? '');
@ -231,7 +235,7 @@ final class Project{
elseif(preg_match('|^https?://(www\.)?github.com/|ius', $this->VcsUrl)){
$this->VcsUrl = rtrim($this->VcsUrl, '/');
if(!preg_match('|^https://github.com/[^/]+/[^/]+$|ius', $this->VcsUrl)){
$error->Add(new Exceptions\InvalidVcsUrlException());
$error->Add(new Exceptions\InvalidVcsUrlException($this->VcsUrl));
}
}

View file

@ -1,6 +1,7 @@
<?
$ebook = $ebook ?? new Ebook();
$isEditForm = $isEditForm ?? false;
$showProjectForm = $showProjectForm ?? true;
?>
<fieldset>
<legend>Contributors</legend>
@ -190,11 +191,11 @@ $isEditForm = $isEditForm ?? false;
</label>
</fieldset>
</details>
<? if(!$isEditForm){ ?>
<? if(!$isEditForm && $showProjectForm){ ?>
<fieldset>
<legend>Project</legend>
<label class="controls-following-fieldset">
<span>In progress?</span>
<span>In progress</span>
<input type="hidden" name="ebook-placeholder-is-in-progress" value="false" />
<input
type="checkbox"
@ -210,7 +211,7 @@ $isEditForm = $isEditForm ?? false;
<fieldset>
<legend>Wanted list</legend>
<label class="controls-following-fieldset">
<span>On the wanted list?</span>
<span>On the wanted list</span>
<input type="hidden" name="ebook-placeholder-is-wanted" value="false" />
<input
type="checkbox"
@ -220,7 +221,7 @@ $isEditForm = $isEditForm ?? false;
</label>
<fieldset>
<label>
<span>Did a Patron request this book?</span>
<span>A Patron requested this book</span>
<input type="hidden" name="ebook-placeholder-is-patron" value="false" />
<input
type="checkbox"
@ -255,6 +256,3 @@ $isEditForm = $isEditForm ?? false;
</label>
</fieldset>
</fieldset>
<div class="footer">
<button>Submit</button>
</div>

View file

@ -2562,6 +2562,10 @@ details summary ~ *{
margin-left: 1rem;
}
fieldset label.controls-following-fieldset + fieldset{
margin-top: -.5rem;
}
fieldset p{
border-bottom: 1px dashed var(--input-border);
}

View file

@ -1,65 +1,65 @@
form.create-update-ebook-placeholder fieldset{
.create-update-ebook-placeholder fieldset{
display: grid;
gap: 2rem;
}
form.create-update-ebook-placeholder details + fieldset,
form.create-update-ebook-placeholder fieldset + fieldset{
.create-update-ebook-placeholder details + fieldset,
.create-update-ebook-placeholder fieldset + fieldset{
margin-top: 2rem;
}
form.create-update-ebook-placeholder > fieldset:nth-of-type(1),
form.create-update-ebook-placeholder details:nth-of-type(1) fieldset{
.create-update-ebook-placeholder > fieldset:nth-of-type(1),
.create-update-ebook-placeholder details:nth-of-type(1) fieldset{
grid-template-columns: 1fr 1fr;
}
form.create-update-ebook-placeholder > fieldset:nth-of-type(2),
form.create-update-ebook-placeholder details:nth-of-type(2) fieldset{
.create-update-ebook-placeholder > fieldset:nth-of-type(2),
.create-update-ebook-placeholder details:nth-of-type(2) fieldset{
grid-template-columns: 1fr 200px;
}
form.create-update-ebook-placeholder fieldset label:has(input[name="ebook-placeholder-transcription-url"]),
form.create-update-ebook-placeholder fieldset label:has(textarea[name="ebook-placeholder-notes"]){
.create-update-ebook-placeholder fieldset label:has(input[name="ebook-placeholder-transcription-url"]),
.create-update-ebook-placeholder fieldset label:has(textarea[name="ebook-placeholder-notes"]){
grid-column: 1 / span 2;
}
form.create-update-ebook-placeholder fieldset:has(input[name="sequence-number-collection-name-1"]),
form.create-update-ebook-placeholder fieldset:has(input[name="sequence-number-collection-name-2"]),
form.create-update-ebook-placeholder fieldset:has(input[name="sequence-number-collection-name-3"]){
.create-update-ebook-placeholder fieldset:has(input[name="sequence-number-collection-name-1"]),
.create-update-ebook-placeholder fieldset:has(input[name="sequence-number-collection-name-2"]),
.create-update-ebook-placeholder fieldset:has(input[name="sequence-number-collection-name-3"]){
display: grid;
grid-template-columns: 1fr 200px 200px;
gap: 2rem;
}
form.create-update-ebook-placeholder fieldset label:has(input[type="checkbox"]){
.create-update-ebook-placeholder fieldset label:has(input[type="checkbox"]){
grid-column: 1 / span 2;
}
form.create-update-ebook-placeholder details{
.create-update-ebook-placeholder details{
margin-top: 1rem;
}
form.create-update-ebook-placeholder summary{
.create-update-ebook-placeholder summary{
font-style: italic;
}
form.create-update-ebook-placeholder p{
.create-update-ebook-placeholder p{
margin-bottom: 1rem;
margin-top: 1.5rem;
font-style: italic;
}
form.create-update-ebook-placeholder fieldset p{
.create-update-ebook-placeholder fieldset p{
font-style: italic;
margin: 0;
border: none;
}
form.create-update-ebook-placeholder fieldset p:first-of-type{
.create-update-ebook-placeholder fieldset p:first-of-type{
margin-top: 0;
}
form.create-update-ebook-placeholder legend{
.create-update-ebook-placeholder legend{
font-size: 1.4rem;
font-family: "League Spartan", Arial, sans-serif;
margin-bottom: 1rem;
@ -68,7 +68,7 @@ form.create-update-ebook-placeholder legend{
text-transform: uppercase;
}
form.create-update-ebook-placeholder label{
.create-update-ebook-placeholder label{
display: block;
}
@ -78,12 +78,12 @@ form div.footer{
}
/* Hide the next fieldset unless the ebook-placeholder-is-wanted checkbox is checked. */
form.create-update-ebook-placeholder label.controls-following-fieldset + fieldset{
.create-update-ebook-placeholder label.controls-following-fieldset + fieldset{
display: none;
grid-column: 1 / span 2;
}
form.create-update-ebook-placeholder label.controls-following-fieldset:has(input[type="checkbox"]:checked) + fieldset{
.create-update-ebook-placeholder label.controls-following-fieldset:has(input[type="checkbox"]:checked) + fieldset{
display: grid;
}

View file

@ -25,6 +25,10 @@
text-align: right;
}
.project-form .placeholder-form{
grid-column: 1 / span 2;
}
table.data-table .status,
table.data-table .producer{
white-space: nowrap;

View file

@ -56,6 +56,9 @@ catch(Exceptions\InvalidPermissionsException){
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="<?= $ebook->Url ?>" autocomplete="off">
<input type="hidden" name="_method" value="<?= Enums\HttpMethod::Put->value ?>" />
<?= Template::EbookPlaceholderForm(['ebook' => $ebook, 'isEditForm' => true]) ?>
<div class="footer">
<button>Save</button>
</div>
</form>
</section>
</main>

View file

@ -82,6 +82,9 @@ catch(Exceptions\InvalidPermissionsException){
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="/ebook-placeholders" autocomplete="off">
<?= Template::EbookPlaceholderForm(['ebook' => $ebook]) ?>
<div class="footer">
<button>Submit</button>
</div>
</form>
</section>
</main>

View file

@ -42,9 +42,9 @@ try{
$_SESSION['is-only-ebook-project-created'] = true;
}
else{
// No `Project`, throw the exception and really fail.
// The existing ebook already has a `Project`, throw the exception and really fail.
$ebook = $existingEbook;
throw $ex;
throw new Exceptions\ProjectExistsException('This ebook already exists, and already has an in-progress project.');
}
}
@ -85,7 +85,7 @@ catch(Exceptions\LoginRequiredException){
catch(Exceptions\InvalidPermissionsException | Exceptions\InvalidHttpMethodException | Exceptions\HttpMethodNotAllowedException){
Template::ExitWithCode(Enums\HttpCode::Forbidden);
}
catch(Exceptions\InvalidEbookException | Exceptions\InvalidProjectException $ex){
catch(Exceptions\InvalidEbookException | Exceptions\ProjectExistsException | Exceptions\InvalidProjectException $ex){
$_SESSION['ebook'] = $ebook;
$_SESSION['exception'] = $ex;

View file

@ -47,10 +47,10 @@ if($exception){
<p>What kind of email would you like to receive?</p>
<ul>
<li>
<label><input type="checkbox" value="1" name="issubscribedtonewsletter"<? if($subscription->IsSubscribedToNewsletter){ ?> checked="checked"<? } ?> />The occasional Standard Ebooks newsletter</label>
<label><input type="checkbox" value="true" name="is-subscribed-to-newsletter"<? if($subscription->IsSubscribedToNewsletter){ ?> checked="checked"<? } ?> />The occasional Standard Ebooks newsletter</label>
</li>
<li>
<label><input type="checkbox" value="1" name="issubscribedtosummary"<? if($subscription->IsSubscribedToSummary){ ?> checked="checked"<? } ?> />A monthly summary of new ebook releases</label>
<label><input type="checkbox" value="true" name="is-subscribed-to-summary"<? if($subscription->IsSubscribedToSummary){ ?> checked="checked"<? } ?> />A monthly summary of new ebook releases</label>
</li>
</ul>
</fieldset>

View file

@ -32,8 +32,8 @@ try{
$subscription->User = new User();
$subscription->User->Email = HttpInput::Str(POST, 'email');
$subscription->IsSubscribedToNewsletter = HttpInput::Bool(POST, 'issubscribedtonewsletter') ?? false;
$subscription->IsSubscribedToSummary = HttpInput::Bool(POST, 'issubscribedtosummary') ?? false;
$subscription->IsSubscribedToNewsletter = HttpInput::Bool(POST, 'is-subscribed-to-newsletter') ?? false;
$subscription->IsSubscribedToSummary = HttpInput::Bool(POST, 'is-subscribed-to-summary') ?? false;
$expectedCaptcha = HttpInput::Str(SESSION, 'captcha') ?? '';
$receivedCaptcha = HttpInput::Str(POST, 'captcha');

View file

@ -19,8 +19,10 @@ try{
session_start();
$isCreated = HttpInput::Bool(SESSION, 'is-project-created') ?? false;
$isOnlyProjectCreated = HttpInput::Bool(SESSION, 'is-only-ebook-project-created') ?? false;
$createdProject = HttpInput::SessionObject('project', Project::class);
if($isCreated){
if($isCreated || $isOnlyProjectCreated){
// We got here because a `Project` was successfully submitted.
http_response_code(Enums\HttpCode::Created->value);
session_unset();
@ -43,9 +45,19 @@ catch(Exceptions\InvalidPermissionsException){
<main>
<section>
<h1>Projects</h1>
<? if(Session::$User->Benefits->CanEditProjects){ ?>
<p>
<a href="/projects/new">New project</a>
</p>
<? } ?>
<? if($createdProject !== null){ ?>
<? if($isCreated){ ?>
<p class="message success">Project for <a href="<?= $createdProject->Ebook->Url ?>"><?= Formatter::EscapeHtml($createdProject->Ebook->Title) ?></a> created!</p>
<? } ?>
<? if($isCreated){ ?>
<p class="message success">Project created!</p>
<? if($isOnlyProjectCreated){ ?>
<p class="message success">An ebook placeholder <a href="<?= $createdProject->Ebook->Url ?>">already exists</a> for this ebook, but a new project was created!</p>
<? } ?>
<? } ?>
<section id="active">

View file

@ -54,7 +54,7 @@ catch(Exceptions\InvalidPermissionsException){
}
?><?= Template::Header([
'title' => 'New Project',
'css' => ['/css/project.css'],
'css' => ['/css/project.css', '/css/ebook-placeholder.css'],
'description' => 'Add a new ebook project.'
]) ?>
<main>
@ -69,7 +69,13 @@ catch(Exceptions\InvalidPermissionsException){
<?= Template::Error(['exception' => $exception]) ?>
<form action="/projects" method="<?= Enums\HttpMethod::Post->value ?>" class="project-form">
<?= Template::ProjectForm(['project' => $project, 'areFieldsRequired' => true]) ?>
<?= Template::ProjectForm(['project' => $project]) ?>
<? if(!isset($project->EbookId)){ ?>
<fieldset class="create-update-ebook-placeholder placeholder-form">
<legend>Placeholder</legend>
<?= Template::EbookPlaceholderForm(['ebook' => $project->Ebook ?? new Ebook(), 'showProjectForm' => false]) ?>
</fieldset>
<? } ?>
<div class="footer">
<button>Submit</button>
</div>

View file

@ -20,7 +20,36 @@ try{
$project->FillFromHttpPost();
$project->Create();
// Are we creating a new placeholder at the same time?
if(!isset($project->EbookId)){
$project->Ebook = new Ebook();
$project->Ebook->FillFromEbookPlaceholderForm();
$project->Ebook->Validate();
$project->Validate(true, true);
try{
$project->Ebook->Create();
$project->EbookId = $project->Ebook->EbookId;
}
catch(Exceptions\DuplicateEbookException $ex){
// If the `Ebook` already exists, create the `Project` anyway.
$project->Ebook = Ebook::GetByIdentifier($project->Ebook->Identifier);
if(!$project->Ebook->EbookPlaceholder?->IsInProgress){
$project->EbookId = $project->Ebook->EbookId;
$_SESSION['is-only-ebook-project-created'] = true;
}
else{
// `Ebook` exists and it's not a placeholder, so really fail.
throw new Exceptions\EbookIsNotAPlaceholderException();
}
}
$project->Create();
}
else{
$project->Create();
}
$_SESSION['project'] = $project;
$_SESSION['is-project-created'] = true;
@ -52,7 +81,7 @@ catch(Exceptions\LoginRequiredException){
catch(Exceptions\InvalidPermissionsException){
Template::ExitWithCode(Enums\HttpCode::Forbidden);
}
catch(Exceptions\InvalidProjectException | Exceptions\ProjectExistsException | Exceptions\EbookIsNotAPlaceholderException $ex){
catch(Exceptions\InvalidProjectException | Exceptions\InvalidEbookException | Exceptions\ProjectExistsException | Exceptions\DuplicateEbookException | Exceptions\EbookIsNotAPlaceholderException $ex){
$_SESSION['project'] = $project;
$_SESSION['exception'] = $ex;