mirror of
https://github.com/standardebooks/web.git
synced 2025-07-16 03:16:36 -04:00
Add new project form, and allow projects to be created when attempting to create a placeholder that already exists.
This commit is contained in:
parent
8e6b05a150
commit
d902074285
17 changed files with 217 additions and 29 deletions
|
@ -53,4 +53,5 @@ RewriteRule ^/ebooks/jules-verne/twenty-thousand-leagues-under-the-seas/f-p-walt
|
||||||
# Prevent this rule from firing if we're getting a distribution file
|
# Prevent this rule from firing if we're getting a distribution file
|
||||||
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/downloads/.+$
|
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/downloads/.+$
|
||||||
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/text.*$
|
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/text.*$
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !^/ebooks/.+?/projects.*$
|
||||||
RewriteRule ^/ebooks/([^\.]+?)$ /ebooks/get.php?url-path=$1
|
RewriteRule ^/ebooks/([^\.]+?)$ /ebooks/get.php?url-path=$1
|
||||||
|
|
1
config/apache/rewrites/projects.conf
Normal file
1
config/apache/rewrites/projects.conf
Normal file
|
@ -0,0 +1 @@
|
||||||
|
RewriteRule ^/ebooks/([^\.]+?)/projects/new$ /projects/new.php?ebook-url-path=$1
|
|
@ -217,6 +217,7 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites
|
||||||
Include ${conf_rewrite_root}/artworks.conf
|
Include ${conf_rewrite_root}/artworks.conf
|
||||||
Include ${conf_rewrite_root}/polls.conf
|
Include ${conf_rewrite_root}/polls.conf
|
||||||
Include ${conf_rewrite_root}/users.conf
|
Include ${conf_rewrite_root}/users.conf
|
||||||
|
Include ${conf_rewrite_root}/projects.conf
|
||||||
|
|
||||||
# Specific config for /ebooks/<author>/<ebook>/downloads
|
# Specific config for /ebooks/<author>/<ebook>/downloads
|
||||||
<DirectoryMatch "^${web_root}/www/ebooks/.+">
|
<DirectoryMatch "^${web_root}/www/ebooks/.+">
|
||||||
|
|
|
@ -199,6 +199,7 @@ Define conf_rewrite_root ${web_root}/config/apache/rewrites
|
||||||
Include ${conf_rewrite_root}/artworks.conf
|
Include ${conf_rewrite_root}/artworks.conf
|
||||||
Include ${conf_rewrite_root}/polls.conf
|
Include ${conf_rewrite_root}/polls.conf
|
||||||
Include ${conf_rewrite_root}/users.conf
|
Include ${conf_rewrite_root}/users.conf
|
||||||
|
Include ${conf_rewrite_root}/projects.conf
|
||||||
|
|
||||||
# Specific config for /ebooks/<author>/<ebook>/downloads
|
# Specific config for /ebooks/<author>/<ebook>/downloads
|
||||||
<DirectoryMatch "^${web_root}/www/ebooks/.+">
|
<DirectoryMatch "^${web_root}/www/ebooks/.+">
|
||||||
|
|
|
@ -191,7 +191,7 @@ class Project{
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isset($this->Started)){
|
if(!isset($this->Started)){
|
||||||
$error->Add(new Exceptions\StartedTimestampRequiredException());
|
$this->Started = NOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($error->HasExceptions){
|
if($error->HasExceptions){
|
||||||
|
@ -356,6 +356,7 @@ class Project{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function FillFromHttpPost(): void{
|
public function FillFromHttpPost(): void{
|
||||||
|
$this->PropertyFromHttp('EbookId');
|
||||||
$this->PropertyFromHttp('ProducerName');
|
$this->PropertyFromHttp('ProducerName');
|
||||||
$this->PropertyFromHttp('ProducerEmail');
|
$this->PropertyFromHttp('ProducerEmail');
|
||||||
$this->PropertyFromHttp('DiscussionUrl');
|
$this->PropertyFromHttp('DiscussionUrl');
|
||||||
|
|
|
@ -70,7 +70,7 @@ $ebook = $ebook ?? new Ebook();
|
||||||
<label class="icon book">
|
<label class="icon book">
|
||||||
<span>Title</span>
|
<span>Title</span>
|
||||||
<input type="text" name="ebook-title" required="required"
|
<input type="text" name="ebook-title" required="required"
|
||||||
value="<?= Formatter::EscapeHtml($ebook->Title ?? '') ?>"/>
|
value="<?= Formatter::EscapeHtml($ebook->Title ?? '') ?>" autocomplete="off"/>
|
||||||
</label>
|
</label>
|
||||||
<label class="icon year">
|
<label class="icon year">
|
||||||
Year published
|
Year published
|
||||||
|
@ -79,6 +79,7 @@ $ebook = $ebook ?? new Ebook();
|
||||||
name="ebook-placeholder-year-published"
|
name="ebook-placeholder-year-published"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
pattern="[0-9]{1,4}"
|
pattern="[0-9]{1,4}"
|
||||||
|
autocomplete="off"
|
||||||
value="<?= Formatter::EscapeHtml((string)($ebook->EbookPlaceholder?->YearPublished)) ?>"
|
value="<?= Formatter::EscapeHtml((string)($ebook->EbookPlaceholder?->YearPublished)) ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -116,6 +117,7 @@ $ebook = $ebook ?? new Ebook();
|
||||||
name="sequence-number-collection-name-1"
|
name="sequence-number-collection-name-1"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
pattern="[0-9]{1,3}"
|
pattern="[0-9]{1,3}"
|
||||||
|
autocomplete="off"
|
||||||
value="<? if(isset($ebook->CollectionMemberships) && sizeof($ebook->CollectionMemberships) > 0){ ?><?= Formatter::EscapeHtml((string)$ebook->CollectionMemberships[0]->SequenceNumber) ?><? } ?>"
|
value="<? if(isset($ebook->CollectionMemberships) && sizeof($ebook->CollectionMemberships) > 0){ ?><?= Formatter::EscapeHtml((string)$ebook->CollectionMemberships[0]->SequenceNumber) ?><? } ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -149,6 +151,7 @@ $ebook = $ebook ?? new Ebook();
|
||||||
name="sequence-number-collection-name-2"
|
name="sequence-number-collection-name-2"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
pattern="[0-9]{1,3}"
|
pattern="[0-9]{1,3}"
|
||||||
|
autocomplete="off"
|
||||||
value="<? if(isset($ebook->CollectionMemberships) && sizeof($ebook->CollectionMemberships) > 1){ ?><?= Formatter::EscapeHtml((string)$ebook->CollectionMemberships[1]->SequenceNumber) ?><? } ?>"
|
value="<? if(isset($ebook->CollectionMemberships) && sizeof($ebook->CollectionMemberships) > 1){ ?><?= Formatter::EscapeHtml((string)$ebook->CollectionMemberships[1]->SequenceNumber) ?><? } ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -180,6 +183,7 @@ $ebook = $ebook ?? new Ebook();
|
||||||
name="sequence-number-collection-name-3"
|
name="sequence-number-collection-name-3"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
pattern="[0-9]{1,3}"
|
pattern="[0-9]{1,3}"
|
||||||
|
autocomplete="off"
|
||||||
value="<? if(isset($ebook->CollectionMemberships) && sizeof($ebook->CollectionMemberships) > 2){ ?><?= Formatter::EscapeHtml((string)$ebook->CollectionMemberships[2]->SequenceNumber) ?><? } ?>"
|
value="<? if(isset($ebook->CollectionMemberships) && sizeof($ebook->CollectionMemberships) > 2){ ?><?= Formatter::EscapeHtml((string)$ebook->CollectionMemberships[2]->SequenceNumber) ?><? } ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -197,7 +201,7 @@ $ebook = $ebook ?? new Ebook();
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<fieldset class="project-form">
|
<fieldset class="project-form">
|
||||||
<?= Template::ProjectForm(['project' => $ebook->ProjectInProgress]) ?>
|
<?= Template::ProjectForm(['project' => $ebook->ProjectInProgress, 'areFieldsRequired' => false]) ?>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
@ -237,6 +241,7 @@ $ebook = $ebook ?? new Ebook();
|
||||||
<input
|
<input
|
||||||
type="url"
|
type="url"
|
||||||
name="ebook-placeholder-transcription-url"
|
name="ebook-placeholder-transcription-url"
|
||||||
|
autocomplete="off"
|
||||||
value="<?= Formatter::EscapeHtml($ebook->EbookPlaceholder?->TranscriptionUrl) ?>"
|
value="<?= Formatter::EscapeHtml($ebook->EbookPlaceholder?->TranscriptionUrl) ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -2,10 +2,15 @@
|
||||||
/**
|
/**
|
||||||
* @var Ebook $ebook
|
* @var Ebook $ebook
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
$showAddButton = $showAddButton ?? false;
|
||||||
?>
|
?>
|
||||||
<? if(sizeof($ebook->Projects) > 0){ ?>
|
<section id="projects">
|
||||||
<section id="projects">
|
<h2>Projects</h2>
|
||||||
<h2>Projects</h2>
|
<? if($showAddButton){ ?>
|
||||||
|
<a href="<?= $ebook->Url ?>/projects/new">New project</a>
|
||||||
|
<? } ?>
|
||||||
|
<? if(sizeof($ebook->Projects) > 0){ ?>
|
||||||
<?= Template::ProjectsTable(['projects' => $ebook->Projects, 'includeTitle' => false]) ?>
|
<?= Template::ProjectsTable(['projects' => $ebook->Projects, 'includeTitle' => false]) ?>
|
||||||
</section>
|
<? } ?>
|
||||||
<? } ?>
|
</section>
|
||||||
|
|
|
@ -2,12 +2,18 @@
|
||||||
$project = $project ?? new Project();
|
$project = $project ?? new Project();
|
||||||
$managers = User::GetAllByCanManageProjects();
|
$managers = User::GetAllByCanManageProjects();
|
||||||
$reviewers = User::GetAllByCanReviewProjects();
|
$reviewers = User::GetAllByCanReviewProjects();
|
||||||
|
$areFieldsRequired = $areFieldsRequired ?? true;
|
||||||
?>
|
?>
|
||||||
|
<input type="hidden" name="project-ebook-id" value="<?= $project->EbookId ?? '' ?>" />
|
||||||
|
|
||||||
<label class="icon user">
|
<label class="icon user">
|
||||||
<span>Producer name</span>
|
<span>Producer name</span>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="project-producer-name"
|
name="project-producer-name"
|
||||||
|
<? if($areFieldsRequired){ ?>
|
||||||
|
required="required"
|
||||||
|
<? } ?>
|
||||||
value="<?= Formatter::EscapeHtml($project->ProducerName ?? '') ?>"
|
value="<?= Formatter::EscapeHtml($project->ProducerName ?? '') ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -72,6 +78,7 @@ $reviewers = User::GetAllByCanReviewProjects();
|
||||||
name="project-vcs-url"
|
name="project-vcs-url"
|
||||||
placeholder="https://github.com/..."
|
placeholder="https://github.com/..."
|
||||||
pattern="^https:\/\/github\.com\/[^\/]+/[^\/]+/?$"
|
pattern="^https:\/\/github\.com\/[^\/]+/[^\/]+/?$"
|
||||||
|
autocomplete="off"
|
||||||
value="<?= Formatter::EscapeHtml($project->VcsUrl ?? '') ?>"
|
value="<?= Formatter::EscapeHtml($project->VcsUrl ?? '') ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
@ -81,6 +88,7 @@ $reviewers = User::GetAllByCanReviewProjects();
|
||||||
<input
|
<input
|
||||||
type="url"
|
type="url"
|
||||||
name="project-discussion-url"
|
name="project-discussion-url"
|
||||||
|
autocomplete="off"
|
||||||
value="<?= Formatter::EscapeHtml($project->DiscussionUrl) ?>"
|
value="<?= Formatter::EscapeHtml($project->DiscussionUrl) ?>"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -3326,6 +3326,13 @@ nav.breadcrumbs + h1{
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extra-line > span:first-child::before{
|
||||||
|
content: 'Spacer';
|
||||||
|
visibility: hidden;
|
||||||
|
display: block;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
@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]{
|
||||||
|
|
|
@ -99,10 +99,3 @@ article.ebook.ebook-placeholder .placeholder-details{
|
||||||
article.ebook.ebook-placeholder .placeholder-details ul{
|
article.ebook.ebook-placeholder .placeholder-details ul{
|
||||||
list-style: disc;
|
list-style: disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extra-line > span:first-child::before{
|
|
||||||
content: 'Spacer';
|
|
||||||
visibility: hidden;
|
|
||||||
display: block;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,6 +12,20 @@
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.project-form{
|
||||||
|
display: grid;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-form label:has(input[type="checkbox"]){
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-form div.footer{
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
table.data-table .status,
|
table.data-table .status,
|
||||||
table.data-table .producer{
|
table.data-table .producer{
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<?
|
<?
|
||||||
|
|
||||||
use function Safe\preg_replace;
|
use function Safe\preg_replace;
|
||||||
|
|
||||||
/** @var string $identifier Passed from script this is included from. */
|
/** @var string $identifier Passed from script this is included from. */
|
||||||
|
@ -108,7 +107,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<? if(Session::$User?->Benefits->CanEditProjects || Session::$User?->Benefits->CanManageProjects || Session::$User?->Benefits->CanReviewProjects){ ?>
|
<? if(Session::$User?->Benefits->CanEditProjects || Session::$User?->Benefits->CanManageProjects || Session::$User?->Benefits->CanReviewProjects){ ?>
|
||||||
<?= Template::EbookProjects(['ebook' => $ebook]) ?>
|
<?= Template::EbookProjects(['ebook' => $ebook, 'showAddButton' => Session::$User->Benefits->CanEditProjects && $ebook->ProjectInProgress === null]) ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</article>
|
</article>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -4,8 +4,10 @@ use function Safe\session_unset;
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
$isCreated = HttpInput::Bool(SESSION, 'is-ebook-placeholder-created') ?? false;
|
$isCreated = HttpInput::Bool(SESSION, 'is-ebook-placeholder-created') ?? false;
|
||||||
|
$isOnlyProjectCreated = HttpInput::Bool(SESSION, 'is-only-ebook-project-created') ?? false;
|
||||||
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
||||||
$ebook = HttpInput::SessionObject('ebook', Ebook::class);
|
$ebook = HttpInput::SessionObject('ebook', Ebook::class);
|
||||||
|
$project = HttpInput::SessionObject('project', Project::class);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(Session::$User === null){
|
if(Session::$User === null){
|
||||||
|
@ -16,7 +18,7 @@ try{
|
||||||
throw new Exceptions\InvalidPermissionsException();
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($isCreated){
|
if($isCreated || $isOnlyProjectCreated){
|
||||||
// We got here because an `Ebook` was successfully created.
|
// We got here because an `Ebook` was successfully created.
|
||||||
http_response_code(Enums\HttpCode::Created->value);
|
http_response_code(Enums\HttpCode::Created->value);
|
||||||
if($ebook !== null){
|
if($ebook !== null){
|
||||||
|
@ -70,8 +72,10 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
|
|
||||||
<?= Template::Error(['exception' => $exception]) ?>
|
<?= Template::Error(['exception' => $exception]) ?>
|
||||||
|
|
||||||
<? if($isCreated && isset($createdEbook)){ ?>
|
<? if($isOnlyProjectCreated){ ?>
|
||||||
<p class="message success">Ebook Placeholder created: <a href="<?= $createdEbook->Url ?>"><?= Formatter::EscapeHtml($createdEbook->Title) ?></a>!</p>
|
<p class="message success">An ebook placeholder <a href="<?= $createdEbook->Url ?>">already exists</a> for this ebook, but a a new project was created!</p>
|
||||||
|
<? }elseif($isCreated && isset($createdEbook)){ ?>
|
||||||
|
<p class="message success">Ebook placeholder created: <a href="<?= $createdEbook->Url ?>"><?= Formatter::EscapeHtml($createdEbook->Title) ?></a>!</p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
|
|
||||||
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="/ebook-placeholders" autocomplete="off">
|
<form class="create-update-ebook-placeholder" method="<?= Enums\HttpMethod::Post->value ?>" action="/ebook-placeholders" autocomplete="off">
|
||||||
|
|
|
@ -85,26 +85,34 @@ try{
|
||||||
}
|
}
|
||||||
|
|
||||||
$ebook->FillIdentifierFromTitleAndContributors();
|
$ebook->FillIdentifierFromTitleAndContributors();
|
||||||
try{
|
|
||||||
$existingEbook = Ebook::GetByIdentifier($ebook->Identifier);
|
|
||||||
throw new Exceptions\DuplicateEbookException($ebook->Identifier);
|
|
||||||
}
|
|
||||||
catch(Exceptions\EbookNotFoundException){
|
|
||||||
// Pass and create the placeholder. There is no existing ebook with this identifier.
|
|
||||||
}
|
|
||||||
|
|
||||||
// These properties must be set before calling `Ebook::Create()` to prevent the getters from triggering DB queries or accessing `Ebook::$EbookId` before it is set.
|
// These properties must be set before calling `Ebook::Create()` to prevent the getters from triggering DB queries or accessing `Ebook::$EbookId` before it is set.
|
||||||
$ebook->Tags = [];
|
$ebook->Tags = [];
|
||||||
$ebook->LocSubjects = [];
|
$ebook->LocSubjects = [];
|
||||||
$ebook->Illustrators = [];
|
$ebook->Illustrators = [];
|
||||||
$ebook->Contributors = [];
|
$ebook->Contributors = [];
|
||||||
$ebook->Create();
|
|
||||||
|
try{
|
||||||
|
$ebook->Create();
|
||||||
|
}
|
||||||
|
catch(Exceptions\DuplicateEbookException $ex){
|
||||||
|
// If the identifier already exists but a `Project` was sent with this request, create the `Project` anyway.
|
||||||
|
$existingEbook = Ebook::GetByIdentifier($ebook->Identifier);
|
||||||
|
if($ebookPlaceholder->IsInProgress && $project !== null){
|
||||||
|
$ebook->EbookId = $existingEbook->EbookId;
|
||||||
|
$_SESSION['is-only-ebook-project-created'] = true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// No `Project`, throw the exception and really fail.
|
||||||
|
$ebook = $existingEbook;
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($ebookPlaceholder->IsInProgress && $project !== null){
|
if($ebookPlaceholder->IsInProgress && $project !== null){
|
||||||
$project->EbookId = $ebook->EbookId;
|
$project->EbookId = $ebook->EbookId;
|
||||||
$project->Ebook = $ebook;
|
$project->Ebook = $ebook;
|
||||||
$project->Create();
|
$project->Create();
|
||||||
$ebook->ProjectInProgress = $project;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$_SESSION['ebook'] = $ebook;
|
$_SESSION['ebook'] = $ebook;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?
|
<?
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(Session::$User === null){
|
if(Session::$User === null){
|
||||||
throw new Exceptions\LoginRequiredException();
|
throw new Exceptions\LoginRequiredException();
|
||||||
|
@ -14,6 +15,16 @@ try{
|
||||||
throw new Exceptions\InvalidPermissionsException();
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$isCreated = HttpInput::Bool(SESSION, 'is-project-created') ?? false;
|
||||||
|
|
||||||
|
if($isCreated){
|
||||||
|
// We got here because a `Project` was successfully submitted.
|
||||||
|
http_response_code(Enums\HttpCode::Created->value);
|
||||||
|
session_unset();
|
||||||
|
}
|
||||||
|
|
||||||
$inProgressProjects = Project::GetAllByStatus(Enums\ProjectStatusType::InProgress);
|
$inProgressProjects = Project::GetAllByStatus(Enums\ProjectStatusType::InProgress);
|
||||||
$stalledProjects = Project::GetAllByStatus(Enums\ProjectStatusType::Stalled);
|
$stalledProjects = Project::GetAllByStatus(Enums\ProjectStatusType::Stalled);
|
||||||
}
|
}
|
||||||
|
@ -31,6 +42,11 @@ catch(Exceptions\InvalidPermissionsException){
|
||||||
<main>
|
<main>
|
||||||
<section>
|
<section>
|
||||||
<h1>Projects</h1>
|
<h1>Projects</h1>
|
||||||
|
|
||||||
|
<? if($isCreated){ ?>
|
||||||
|
<p class="message success">Project created!</p>
|
||||||
|
<? } ?>
|
||||||
|
|
||||||
<section id="active">
|
<section id="active">
|
||||||
<h2>Active projects</h2>
|
<h2>Active projects</h2>
|
||||||
<? if(sizeof($inProgressProjects) == 0){ ?>
|
<? if(sizeof($inProgressProjects) == 0){ ?>
|
||||||
|
|
79
www/projects/new.php
Normal file
79
www/projects/new.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?
|
||||||
|
/**
|
||||||
|
* GET /ebooks/<ebook-identifier>/projects/new
|
||||||
|
* GET /projects/new
|
||||||
|
*/
|
||||||
|
|
||||||
|
use function Safe\session_unset;
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$urlPath = HttpInput::Str(GET, 'ebook-url-path');
|
||||||
|
$exception = HttpInput::SessionObject('exception', Exceptions\AppException::class);
|
||||||
|
$project = HttpInput::SessionObject('project', Project::class);
|
||||||
|
$ebook = null;
|
||||||
|
|
||||||
|
try{
|
||||||
|
if($urlPath !== null){
|
||||||
|
// Check this first so we can output a 404 immediately if it's not found.
|
||||||
|
$identifier = EBOOKS_IDENTIFIER_PREFIX . trim(str_replace('.', '', $urlPath), '/'); // Contains the portion of the URL (without query string) that comes after `https://standardebooks.org/ebooks/`.
|
||||||
|
|
||||||
|
$ebook = Ebook::GetByIdentifier($identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Session::$User === null){
|
||||||
|
throw new Exceptions\LoginRequiredException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Session::$User->Benefits->CanEditProjects){
|
||||||
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($exception){
|
||||||
|
// We got here because a `Project` submission had errors and the user has to try again.
|
||||||
|
http_response_code(Enums\HttpCode::UnprocessableContent->value);
|
||||||
|
session_unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if($project === null){
|
||||||
|
$project = new Project();
|
||||||
|
if($ebook !== null){
|
||||||
|
$project->Ebook = $ebook;
|
||||||
|
$project->EbookId = $ebook->EbookId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exceptions\EbookNotFoundException){
|
||||||
|
Template::Emit404();
|
||||||
|
}
|
||||||
|
catch(Exceptions\LoginRequiredException){
|
||||||
|
Template::RedirectToLogin();
|
||||||
|
}
|
||||||
|
catch(Exceptions\InvalidPermissionsException){
|
||||||
|
Template::Emit403();
|
||||||
|
}
|
||||||
|
?><?= Template::Header([
|
||||||
|
'title' => 'New Project',
|
||||||
|
'css' => ['/css/project.css'],
|
||||||
|
'description' => 'Add a new ebook project.'
|
||||||
|
]) ?>
|
||||||
|
<main>
|
||||||
|
<section class="narrow">
|
||||||
|
<? if(isset($project->Ebook)){ ?>
|
||||||
|
<nav class="breadcrumbs">
|
||||||
|
<a href="<?= $project->Ebook->AuthorsUrl ?>"><?= $project->Ebook->AuthorsHtml ?></a> → <a href="<?= $project->Ebook->Url ?>"><?= Formatter::EscapeHtml($project->Ebook->Title) ?></a> →
|
||||||
|
</nav>
|
||||||
|
<? } ?>
|
||||||
|
<h1>New Project</h1>
|
||||||
|
|
||||||
|
<?= Template::Error(['exception' => $exception]) ?>
|
||||||
|
|
||||||
|
<form action="/projects" method="<?= Enums\HttpMethod::Post->value ?>" class="project-form">
|
||||||
|
<?= Template::ProjectForm(['project' => $project, 'areFieldsRequired' => true]) ?>
|
||||||
|
<div class="footer">
|
||||||
|
<button>Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<?= Template::Footer() ?>
|
45
www/projects/post.php
Normal file
45
www/projects/post.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?
|
||||||
|
|
||||||
|
try{
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$httpMethod = HttpInput::ValidateRequestMethod([Enums\HttpMethod::Post, Enums\HttpMethod::Patch, Enums\HttpMethod::Put]);
|
||||||
|
|
||||||
|
if(Session::$User === null){
|
||||||
|
throw new Exceptions\LoginRequiredException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Session::$User->Benefits->CanEditProjects){
|
||||||
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// POSTing a new `Project`.
|
||||||
|
if($httpMethod == Enums\HttpMethod::Post){
|
||||||
|
$project = new Project();
|
||||||
|
$project->FillFromHttpPost();
|
||||||
|
|
||||||
|
$project->Create();
|
||||||
|
|
||||||
|
$_SESSION['project'] = $project;
|
||||||
|
$_SESSION['is-project-created'] = true;
|
||||||
|
|
||||||
|
http_response_code(Enums\HttpCode::SeeOther->value);
|
||||||
|
header('Location: /projects');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exceptions\EbookNotFoundException){
|
||||||
|
Template::Emit404();
|
||||||
|
}
|
||||||
|
catch(Exceptions\LoginRequiredException){
|
||||||
|
Template::RedirectToLogin();
|
||||||
|
}
|
||||||
|
catch(Exceptions\InvalidPermissionsException){
|
||||||
|
Template::Emit403();
|
||||||
|
}
|
||||||
|
catch(Exceptions\InvalidProjectException | Exceptions\ProjectExistsException | Exceptions\EbookIsNotAPlaceholderException $ex){
|
||||||
|
$_SESSION['project'] = $project;
|
||||||
|
$_SESSION['exception'] = $ex;
|
||||||
|
|
||||||
|
http_response_code(Enums\HttpCode::SeeOther->value);
|
||||||
|
header('Location: /projects/new');
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue