diff --git a/config/sql/se/Benefits.sql b/config/sql/se/Benefits.sql index b8f63236..2cd9161a 100644 --- a/config/sql/se/Benefits.sql +++ b/config/sql/se/Benefits.sql @@ -10,6 +10,8 @@ CREATE TABLE IF NOT EXISTS `Benefits` ( `CanEditCollections` tinyint(1) unsigned NOT NULL DEFAULT 0, `CanEditEbooks` tinyint(1) unsigned NOT NULL DEFAULT 0, `CanCreateEbookPlaceholders` tinyint(1) unsigned NOT NULL DEFAULT 0, + `CanManageProjects` tinyint(1) unsigned NOT NULL DEFAULT 0, + `CanReviewProjects` tinyint(1) unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`UserId`), KEY `idxBenefits` (`CanAccessFeeds`,`CanVote`,`CanBulkDownload`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/config/sql/se/Projects.sql b/config/sql/se/Projects.sql index 947b4664..788c5ebf 100644 --- a/config/sql/se/Projects.sql +++ b/config/sql/se/Projects.sql @@ -2,7 +2,7 @@ CREATE TABLE IF NOT EXISTS `Projects` ( `ProjectId` int(10) unsigned NOT NULL AUTO_INCREMENT, `Status` enum('in_progress','stalled','completed','abandoned') NOT NULL DEFAULT 'in_progress', `EbookId` int(11) NOT NULL, - `ProducerName` varchar(151) DEFAULT NULL, + `ProducerName` varchar(151) NOT NULL DEFAULT '', `ProducerEmail` varchar(80) DEFAULT NULL, `DiscussionUrl` varchar(255) DEFAULT NULL, `VcsUrl` varchar(255) NOT NULL, diff --git a/lib/Collection.php b/lib/Collection.php index 66e74a11..6360cee9 100644 --- a/lib/Collection.php +++ b/lib/Collection.php @@ -109,10 +109,10 @@ class Collection{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidCollectionException */ public function Validate(): void{ - $error = new Exceptions\ValidationException(); + $error = new Exceptions\InvalidCollectionException(); if(isset($this->Name)){ $this->Name = trim($this->Name); @@ -154,7 +154,7 @@ class Collection{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidCollectionException */ public function Create(): void{ $this->Validate(); @@ -169,7 +169,7 @@ class Collection{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidCollectionException */ public function GetByUrlNameOrCreate(string $urlName): Collection{ $result = Db::Query(' diff --git a/lib/Contributor.php b/lib/Contributor.php index 33ab0b45..f9c8c6d2 100644 --- a/lib/Contributor.php +++ b/lib/Contributor.php @@ -64,10 +64,10 @@ class Contributor{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidContributorException */ public function Validate(): void{ - $error = new Exceptions\ValidationException(); + $error = new Exceptions\InvalidContributorException(); if(!isset($this->EbookId)){ $error->Add(new Exceptions\ContributorEbookIdRequiredException()); @@ -140,7 +140,7 @@ class Contributor{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidContributorException */ public function Create(): void{ $this->Validate(); diff --git a/lib/Ebook.php b/lib/Ebook.php index 9198a410..7be5f8e4 100644 --- a/lib/Ebook.php +++ b/lib/Ebook.php @@ -42,6 +42,8 @@ use function Safe\shell_exec; * @property string $TextSinglePageSizeFormatted * @property string $IndexableText * @property ?EbookPlaceholder $EbookPlaceholder + * @property array $Projects + * @property ?Project $ProjectInProgress */ class Ebook{ use Traits\Accessor; @@ -118,11 +120,48 @@ class Ebook{ protected string $_TextSinglePageSizeFormatted; protected string $_IndexableText; protected ?EbookPlaceholder $_EbookPlaceholder = null; + /** @var array $_Projects */ + protected array $_Projects; + protected ?Project $_ProjectInProgress; // ******* // GETTERS // ******* + /** + * @return array + */ + protected function GetProjects(): array{ + if(!isset($this->_Projects)){ + $this->_Projects = Db::Query(' + SELECT * + from Projects + where EbookId = ? + order by Created desc + ', [$this->EbookId], Project::class); + } + + return $this->_Projects; + } + + protected function GetProjectInProgress(): ?Project{ + if(!isset($this->_ProjectInProgress)){ + if(!isset($this->EbookId)){ + $this->_ProjectInProgress = null; + } + else{ + $this->_ProjectInProgress = Db::Query(' + SELECT * + from Projects + where EbookId = ? + and Status in (?, ?) + ', [$this->EbookId, Enums\ProjectStatusType::InProgress, Enums\ProjectStatusType::Stalled], Project::class)[0] ?? null; + } + } + + return $this->_ProjectInProgress; + } + /** * @return array */ @@ -1048,10 +1087,10 @@ class Ebook{ // ******* /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookException */ public function Validate(): void{ - $error = new Exceptions\ValidationException(); + $error = new Exceptions\InvalidEbookException(); if(isset($this->Identifier)){ $this->Identifier = trim($this->Identifier); @@ -1335,17 +1374,13 @@ class Ebook{ $error->Add(new Exceptions\EbookMissingPlaceholderException()); } - if(!$this->IsPlaceholder() && isset($this->EbookPlaceholder)){ - $error->Add(new Exceptions\EbookUnexpectedPlaceholderException()); - } - if($error->HasExceptions){ throw $error; } } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookException * @throws Exceptions\DuplicateEbookException */ public function CreateOrUpdate(): void{ @@ -1360,7 +1395,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookTagException */ private function CreateTags(): void{ $tags = []; @@ -1371,7 +1406,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidLocSubjectException */ private function CreateLocSubjects(): void{ $subjects = []; @@ -1382,7 +1417,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidCollectionException */ private function CreateCollections(): void{ $collectionMemberships = []; @@ -1633,7 +1668,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookException * @throws Exceptions\DuplicateEbookException If an `Ebook` with the given identifier already exists. */ public function Create(): void{ @@ -1647,9 +1682,16 @@ class Ebook{ // Pass. } - $this->CreateTags(); - $this->CreateLocSubjects(); - $this->CreateCollections(); + try{ + $this->CreateTags(); + $this->CreateLocSubjects(); + $this->CreateCollections(); + } + catch(Exceptions\ValidationException $ex){ + $error = new Exceptions\InvalidEbookException(); + $error->Add($ex); + throw $error; + } Db::Query(' INSERT into Ebooks (Identifier, WwwFilesystemPath, RepoFilesystemPath, KindleCoverUrl, EpubUrl, @@ -1687,25 +1729,39 @@ class Ebook{ $this->EbookId = Db::GetLastInsertedId(); - $this->AddTags(); - $this->AddLocSubjects(); - $this->AddCollectionMemberships(); - $this->AddGitCommits(); - $this->AddSources(); - $this->AddContributors(); - $this->AddTocEntries(); - $this->AddEbookPlaceholder(); + try{ + $this->AddTags(); + $this->AddLocSubjects(); + $this->AddCollectionMemberships(); + $this->AddGitCommits(); + $this->AddSources(); + $this->AddContributors(); + $this->AddTocEntries(); + $this->AddEbookPlaceholder(); + } + catch(Exceptions\ValidationException $ex){ + $error = new Exceptions\InvalidEbookException(); + $error->Add($ex); + throw $error; + } } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookException */ public function Save(): void{ $this->Validate(); - $this->CreateTags(); - $this->CreateLocSubjects(); - $this->CreateCollections(); + try{ + $this->CreateTags(); + $this->CreateLocSubjects(); + $this->CreateCollections(); + } + catch(Exceptions\ValidationException $ex){ + $error = new Exceptions\InvalidEbookException(); + $error->Add($ex); + throw $error; + } Db::Query(' UPDATE Ebooks @@ -1742,29 +1798,37 @@ class Ebook{ $this->EbookCreated, $this->EbookUpdated, $this->TextSinglePageByteCount, $this->IndexableText, $this->EbookId]); - $this->RemoveTags(); - $this->AddTags(); - $this->RemoveLocSubjects(); - $this->AddLocSubjects(); + try{ + $this->RemoveTags(); + $this->AddTags(); - $this->RemoveCollectionMemberships(); - $this->AddCollectionMemberships(); + $this->RemoveLocSubjects(); + $this->AddLocSubjects(); - $this->RemoveGitCommits(); - $this->AddGitCommits(); + $this->RemoveCollectionMemberships(); + $this->AddCollectionMemberships(); - $this->RemoveSources(); - $this->AddSources(); + $this->RemoveGitCommits(); + $this->AddGitCommits(); - $this->RemoveContributors(); - $this->AddContributors(); + $this->RemoveSources(); + $this->AddSources(); - $this->RemoveTocEntries(); - $this->AddTocEntries(); + $this->RemoveContributors(); + $this->AddContributors(); - $this->RemoveEbookPlaceholder(); - $this->AddEbookPlaceholder(); + $this->RemoveTocEntries(); + $this->AddTocEntries(); + + $this->RemoveEbookPlaceholder(); + $this->AddEbookPlaceholder(); + } + catch(Exceptions\ValidationException $ex){ + $error = new Exceptions\InvalidEbookException(); + $error->Add($ex); + throw $error; + } } private function RemoveTags(): void{ @@ -1854,7 +1918,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidGitCommitException */ private function AddGitCommits(): void{ foreach($this->GitCommits as $commit){ @@ -1872,7 +1936,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidSourceException */ private function AddSources(): void{ foreach($this->Sources as $sortOrder => $source){ @@ -1891,7 +1955,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidContributorException */ private function AddContributors(): void{ $allContributors = array_merge($this->Authors, $this->Illustrators, $this->Translators, $this->Contributors); @@ -1932,7 +1996,7 @@ class Ebook{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookPlaceholderException */ private function AddEbookPlaceholder(): void{ if(isset($this->EbookPlaceholder)){ diff --git a/lib/EbookPlaceholder.php b/lib/EbookPlaceholder.php index db01350f..ec394170 100644 --- a/lib/EbookPlaceholder.php +++ b/lib/EbookPlaceholder.php @@ -73,11 +73,11 @@ class EbookPlaceholder{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookPlaceholderException */ public function Validate(): void{ $thisYear = intval(NOW->format('Y')); - $error = new Exceptions\ValidationException(); + $error = new Exceptions\InvalidEbookPlaceholderException(); if(isset($this->YearPublished) && ($this->YearPublished <= 0 || $this->YearPublished > $thisYear)){ $error->Add(new Exceptions\InvalidEbookPlaceholderYearPublishedException()); @@ -99,7 +99,7 @@ class EbookPlaceholder{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookPlaceholderException */ public function Create(): void{ $this->Validate(); @@ -117,4 +117,13 @@ class EbookPlaceholder{ ', [$this->EbookId, $this->YearPublished, $this->Difficulty, $this->TranscriptionUrl, $this->IsWanted, $this->IsInProgress, $this->IsPatron, $this->Notes]); } + + public function Delete(): void{ + Db::Query(' + DELETE + from EbookPlaceholders + where EbookId = ? + ', + [$this->EbookId]); + } } diff --git a/lib/EbookSource.php b/lib/EbookSource.php index 46b1e9d1..811c7e1c 100644 --- a/lib/EbookSource.php +++ b/lib/EbookSource.php @@ -14,10 +14,10 @@ class EbookSource{ // ******* /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidSourceException */ public function Validate(): void{ - $error = new Exceptions\ValidationException(); + $error = new Exceptions\InvalidSourceException(); if(!isset($this->EbookId)){ $error->Add(new Exceptions\EbookSourceEbookIdRequiredException()); @@ -44,7 +44,7 @@ class EbookSource{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidSourceException */ public function Create(): void{ $this->Validate(); diff --git a/lib/EbookTag.php b/lib/EbookTag.php index 67a21726..e56f6ef1 100644 --- a/lib/EbookTag.php +++ b/lib/EbookTag.php @@ -23,10 +23,10 @@ class EbookTag extends Tag{ // ******* /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookTagException */ public function Validate(): void{ - $error = new Exceptions\ValidationException(); + $error = new Exceptions\InvalidEbookTagException(); if(isset($this->Name)){ $this->Name = trim($this->Name); @@ -55,7 +55,7 @@ class EbookTag extends Tag{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookTagException */ public function Create(): void{ $this->Validate(); @@ -75,7 +75,7 @@ class EbookTag extends Tag{ // *********** /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidEbookTagException */ public function GetByNameOrCreate(string $name): EbookTag{ $result = Db::Query(' diff --git a/lib/Enums/ProjectStatusType.php b/lib/Enums/ProjectStatusType.php new file mode 100644 index 00000000..b1134ecd --- /dev/null +++ b/lib/Enums/ProjectStatusType.php @@ -0,0 +1,16 @@ + 'in progress', + default => $this->value + }; + } +} diff --git a/lib/Exceptions/EbookIsNotAPlaceholderException.php b/lib/Exceptions/EbookIsNotAPlaceholderException.php new file mode 100644 index 00000000..c1a266b7 --- /dev/null +++ b/lib/Exceptions/EbookIsNotAPlaceholderException.php @@ -0,0 +1,7 @@ +EbookId)){ $error->Add(new Exceptions\GitCommitEbookIdRequiredException()); @@ -83,7 +83,7 @@ class GitCommit{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidGitCommitException */ public function Create(): void{ $this->Validate(); diff --git a/lib/LocSubject.php b/lib/LocSubject.php index c7354630..040bffe9 100644 --- a/lib/LocSubject.php +++ b/lib/LocSubject.php @@ -8,10 +8,10 @@ class LocSubject{ // ******* /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidLocSubjectException */ public function Validate(): void{ - $error = new Exceptions\ValidationException(); + $error = new Exceptions\InvalidLocSubjectException(); if(isset($this->Name)){ $this->Name = trim($this->Name); @@ -34,7 +34,7 @@ class LocSubject{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidLocSubjectException */ public function Create(): void{ $this->Validate(); @@ -47,7 +47,7 @@ class LocSubject{ } /** - * @throws Exceptions\ValidationException + * @throws Exceptions\InvalidLocSubjectException */ public function GetByNameOrCreate(string $name): LocSubject{ $result = Db::Query(' diff --git a/lib/Project.php b/lib/Project.php new file mode 100644 index 00000000..272fe5f5 --- /dev/null +++ b/lib/Project.php @@ -0,0 +1,221 @@ +_Url)){ + $this->_Url = '/projects/' . $this->ProjectId; + } + + return $this->_Url; + } + + /** + * @throws Exceptions\InvalidProjectException If the `Project` is invalid. + */ + public function Validate(): void{ + $error = new Exceptions\InvalidProjectException(); + + if(!isset($this->EbookId)){ + $error->Add(new Exceptions\EbookRequiredException()); + } + + $this->ProducerEmail = trim($this->ProducerEmail ?? ''); + if($this->ProducerEmail == ''){ + $this->ProducerEmail = null; + } + + // If we have an email address, try to see if we have a matching `User` in the database that we can pull the name from. + if($this->ProducerEmail !== null){ + try{ + $user = User::GetByEmail($this->ProducerEmail); + if($user->Name !== null){ + $this->ProducerName = $user->Name; + } + } + catch(Exceptions\UserNotFoundException){ + // Pass. + } + } + + $this->ProducerName = trim($this->ProducerName ?? ''); + if($this->ProducerName == ''){ + $error->Add(new Exceptions\ProducerNameRequiredException()); + } + + $this->DiscussionUrl = trim($this->DiscussionUrl ?? ''); + if($this->DiscussionUrl == ''){ + $this->DiscussionUrl = null; + } + + $this->VcsUrl = rtrim(trim($this->VcsUrl ?? ''), '/'); + if($this->VcsUrl == ''){ + $error->Add(new Exceptions\VcsUrlRequiredException()); + } + elseif(!preg_match('|^https://github.com/[^/]+/[^/]+|ius', $this->VcsUrl)){ + $error->Add(new Exceptions\InvalidVcsUrlException()); + } + + if(!isset($this->ManagerUserId)){ + $error->Add(new Exceptions\ManagerRequiredException()); + } + else{ + try{ + $this->_ManagerUser = User::Get($this->ManagerUserId); + } + catch(Exceptions\UserNotFoundException){ + $error->Add(new Exceptions\UserNotFoundException('Manager user not found.')); + } + } + + if(!isset($this->ReviewerUserId)){ + $error->Add(new Exceptions\ManagerRequiredException()); + } + else{ + try{ + $this->_ReviewerUser = User::Get($this->ReviewerUserId); + } + catch(Exceptions\UserNotFoundException){ + $error->Add(new Exceptions\UserNotFoundException('Reviewer user not found.')); + } + } + + if(!isset($this->Started)){ + $error->Add(new Exceptions\StartedTimestampRequiredException()); + } + + if($error->HasExceptions){ + throw $error; + } + } + + /** + * @throws Exceptions\InvalidProjectException If the `Project` is invalid. + * @throws Exceptions\EbookIsNotAPlaceholderException If the `Project`'s `Ebook` is not a placeholder. + * @throws Exceptions\ProjectExistsException If the `Project`'s `Ebook` already has an active `Project`. + */ + public function Create(): void{ + $this->Validate(); + + // Is this ebook already released? + if(!$this->Ebook->IsPlaceholder()){ + throw new Exceptions\EbookIsNotAPlaceholderException(); + } + + // Does this `Ebook` already has an active `Project`? + if($this->Ebook->ProjectInProgress !== null){ + throw new Exceptions\ProjectExistsException(); + } + + Db::Query(' + INSERT into Projects + ( + EbookId, + Status, + ProducerName, + ProducerEmail, + DiscussionUrl, + VcsUrl, + Created, + Updated, + Started, + Ended, + ManagerUserId, + ReviewerUserId + ) + values + ( + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ? + ) + ', [$this->EbookId, $this->Status, $this->ProducerName, $this->ProducerEmail, $this->DiscussionUrl, $this->VcsUrl, NOW, NOW, $this->Started, $this->Ended, $this->ManagerUserId, $this->ReviewerUserId]); + + $this->ProjectId = Db::GetLastInsertedId(); + } + + /** + * @throws Exceptions\InvalidProjectException If the `Project` is invalid. + */ + public function Save(): void{ + $this->Validate(); + + Db::Query(' + UPDATE + Projects + set + Status = ?, + ProducerName = ?, + ProducerEmail = ?, + DiscussionUrl = ?, + VcsUrl = ?, + Started = ?, + Ended = ?, + ManagerUserId = ?, + ReviewerUserId = ? + where + ProjectId = ? + ', [$this->Status, $this->ProducerName, $this->ProducerEmail, $this->DiscussionUrl, $this->VcsUrl, $this->Started, $this->Ended, $this->ManagerUserId, $this->ReviewerUserId, $this->ProjectId]); + + if($this->Status == Enums\ProjectStatusType::Abandoned){ + Db::Query(' + UPDATE + EbookPlaceholders + set + IsInProgress = false + where + EbookId = ? + ', [$this->EbookId]); + } + } + + public function FillFromHttpPost(): void{ + $this->PropertyFromHttp('ProducerName'); + $this->PropertyFromHttp('ProducerEmail'); + $this->PropertyFromHttp('DiscussionUrl'); + $this->PropertyFromHttp('Status'); + $this->PropertyFromHttp('VcsUrl'); + $this->PropertyFromHttp('Started'); + $this->PropertyFromHttp('Ended'); + $this->PropertyFromHttp('ManagerUserId'); + $this->PropertyFromHttp('ReviewerUserId'); + } +} diff --git a/lib/User.php b/lib/User.php index 02fda675..2cc6f5fa 100644 --- a/lib/User.php +++ b/lib/User.php @@ -345,6 +345,34 @@ class User{ ', [$uuid], User::class)[0] ?? throw new Exceptions\UserNotFoundException(); } + /** + * @return array + */ + public static function GetAllByCanManageProjects(): array{ + return Db::Query(' + SELECT u.* + from Users u + inner join Benefits b + using (UserId) + where b.CanManageProjects = true + order by Name asc + ', [], User::class); + } + + /** + * @return array + */ + public static function GetAllByCanReviewProjects(): array{ + return Db::Query(' + SELECT u.* + from Users u + inner join Benefits b + using (UserId) + where b.CanReviewProjects = true + order by Name asc + ', [], User::class); + } + /** * Get a `User` if they are considered "registered". * diff --git a/scripts/update-ebook-database b/scripts/update-ebook-database index 726067ff..0ec8219e 100755 --- a/scripts/update-ebook-database +++ b/scripts/update-ebook-database @@ -39,6 +39,18 @@ if($verbose){ try{ $ebook->CreateOrUpdate(); + + // If there was an `EbookPlaceholder` for this ebook, delete it. + if($ebook->EbookPlaceholder !== null){ + $ebook->EbookPlaceholder->Delete(); + } + + // If there was a `Project` for this ebook, mark it as completed. + if($ebook->ProjectInProgress !== null){ + $ebook->ProjectInProgress->Status = Enums\ProjectStatusType::Completed; + $ebook->ProjectInProgress->Ended = NOW; + $ebook->ProjectInProgress->Save(); + } } catch(Exceptions\ValidationException $validationException){ $exceptions = $validationException->Exceptions; diff --git a/templates/EbookMetadata.php b/templates/EbookMetadata.php new file mode 100644 index 00000000..7f1bcdc2 --- /dev/null +++ b/templates/EbookMetadata.php @@ -0,0 +1,34 @@ + +

Metadata

+ + + + + + + + + + + Projects) > 0){ ?> + + + + + + +
Ebook ID:EbookId ?>
Identifier:Identifier) ?>
Projects: +
    + Projects as $project){ ?> +
  • +

    + Started->format(Enums\DateTimeFormat::FullDateTime->value) ?> — Status->GetDisplayName() ?> — ProducerEmail !== null){ ?>ProducerName) ?>ProducerName) ?>Link +

    +
  • + +
+
diff --git a/templates/EbookPlaceholderForm.php b/templates/EbookPlaceholderForm.php index 9ae5ab33..e029698a 100644 --- a/templates/EbookPlaceholderForm.php +++ b/templates/EbookPlaceholderForm.php @@ -1,9 +1,5 @@
Contributors @@ -84,7 +80,7 @@ $ebook = $ebook ?? new Ebook(); name="ebook-placeholder-year-published" inputmode="numeric" pattern="[0-9]{1,4}" - value="EbookPlaceholder?->YearPublished)) ?>" + value="EbookPlaceholder?->YearPublished)) ?>" />
@@ -165,16 +161,21 @@ $ebook = $ebook ?? new Ebook();
- -
+
Wanted list
@@ -192,7 +193,7 @@ $ebook = $ebook ?? new Ebook(); EbookPlaceholder?->IsPatron){ ?>checked="checked" + EbookPlaceholder?->IsPatron){ ?>checked="checked" /> @@ -211,13 +212,13 @@ $ebook = $ebook ?? new Ebook();
diff --git a/templates/ProjectForm.php b/templates/ProjectForm.php new file mode 100644 index 00000000..333ae035 --- /dev/null +++ b/templates/ProjectForm.php @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + diff --git a/www/css/core.css b/www/css/core.css index d177d0b7..fa39d4fc 100644 --- a/www/css/core.css +++ b/www/css/core.css @@ -2516,6 +2516,14 @@ fieldset{ border: none; } +label.controls-following-fieldset + fieldset{ + display: none; +} + +label.controls-following-fieldset:has(input[type="checkbox"]:checked) + fieldset{ + display: block; +} + label.controls-following-fieldset + fieldset, details summary ~ *{ margin-left: 1rem; diff --git a/www/css/ebook-placeholder.css b/www/css/ebook-placeholder.css index 44840cc8..4ff74dcc 100644 --- a/www/css/ebook-placeholder.css +++ b/www/css/ebook-placeholder.css @@ -73,12 +73,12 @@ form div.footer{ } /* Hide the next fieldset unless the ebook-placeholder-is-wanted checkbox is checked. */ -form.create-update-ebook-placeholder fieldset:has(input[name="ebook-placeholder-is-wanted"]) fieldset{ +form.create-update-ebook-placeholder label.controls-following-fieldset + fieldset{ display: none; grid-column: 1 / span 2; } -form.create-update-ebook-placeholder fieldset:has(input[name="ebook-placeholder-is-wanted"]:checked) fieldset{ +form.create-update-ebook-placeholder label.controls-following-fieldset:has(input[type="checkbox"]:checked) + fieldset{ display: grid; } diff --git a/www/css/project.css b/www/css/project.css new file mode 100644 index 00000000..f80fe82b --- /dev/null +++ b/www/css/project.css @@ -0,0 +1,13 @@ +.project-form{ + display: grid; + grid-template-columns: 1fr 1fr; +} + +.project-form label:has(input[type="url"]){ + grid-column: 1 / span 2 +} + + +.project-form label:has(input[name="project-manager-user-id"]){ + grid-column-start: 1; +} diff --git a/www/ebook-placeholders/get.php b/www/ebook-placeholders/get.php index 2bbf1cda..aef45b14 100644 --- a/www/ebook-placeholders/get.php +++ b/www/ebook-placeholders/get.php @@ -76,7 +76,7 @@ catch(Exceptions\EbookNotFoundException){ -
+
EbookPlaceholder->IsPublicDomain){ ?> EbookPlaceholder->IsInProgress){ ?>

We don’t have this ebook in our catalog yet, but someone is working on it now! We hope to have it available for you to read very soon.

@@ -87,7 +87,7 @@ catch(Exceptions\EbookNotFoundException){

Sponsor this ebook and we’ll get working on it immediately, so that you and everyone can read it for free forever. You can also choose to have your name inscribed in the ebook’s colophon.

  • - EbookPlaceholder->Difficulty == \Enums\EbookPlaceholderDifficulty::Beginner){ ?> + EbookPlaceholder->Difficulty == Enums\EbookPlaceholderDifficulty::Beginner){ ?>

    Produce this ebook yourself and your work will allow others to read it for free forever. This book is a good choice to start with if you’ve never created an ebook for us before—we’ll help you through the process!

    If you’ve created an ebook for us before, you can produce this ebook yourself so that others can read it for free. Your name will be inscribed in the colophon as the ebook’s producer.

    @@ -105,19 +105,7 @@ catch(Exceptions\EbookNotFoundException){ Benefits->CanEditEbooks){ ?>
    -

    Metadata

    - - - - - - - - - - - -
    Ebook ID:EbookId ?>
    Identifier:Identifier) ?>
    + $ebook]) ?>
    diff --git a/www/ebook-placeholders/new.php b/www/ebook-placeholders/new.php index ac6fb2a0..f04e0d9f 100644 --- a/www/ebook-placeholders/new.php +++ b/www/ebook-placeholders/new.php @@ -26,8 +26,11 @@ try{ // If the `EbookPlaceholder` we just added is part of a collection, prefill the form with the same data to make it easier to submit series. unset($ebook->EbookId); unset($ebook->Title); + unset($ebook->ProjectInProgress); if($ebook->EbookPlaceholder !== null){ $ebook->EbookPlaceholder->YearPublished = null; + $ebook->EbookPlaceholder->IsWanted = false; + $ebook->EbookPlaceholder->IsInProgress = false; } foreach($ebook->CollectionMemberships as $collectionMembership){ $collectionMembership->SequenceNumber++; @@ -56,7 +59,7 @@ catch(Exceptions\InvalidPermissionsException){ 'Create an Ebook Placeholder', - 'css' => ['/css/ebook-placeholder.css'], + 'css' => ['/css/ebook-placeholder.css', '/css/project.css'], 'highlight' => '', 'description' => 'Create a placeholder for an ebook not yet in the collection.' ] diff --git a/www/ebook-placeholders/post.php b/www/ebook-placeholders/post.php index e363d8cb..2ca57f26 100644 --- a/www/ebook-placeholders/post.php +++ b/www/ebook-placeholders/post.php @@ -82,6 +82,16 @@ try{ // Pass and create the placeholder. There is no existing ebook with this identifier. } + // Do we have a `Project` to create at the same time? + $project = null; + if($ebookPlaceholder->IsInProgress){ + $project = new Project(); + $project->FillFromHttpPost(); + $project->Started = NOW; + $project->EbookId = 0; // Dummy value to pass validation, we'll set it to the real value before creating the `Project`. + $project->Validate(); + } + // 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->LocSubjects = []; @@ -89,6 +99,13 @@ try{ $ebook->Contributors = []; $ebook->Create(); + if($ebookPlaceholder->IsInProgress && $project !== null){ + $project->EbookId = $ebook->EbookId; + $project->Ebook = $ebook; + $project->Create(); + $ebook->ProjectInProgress = $project; + } + $_SESSION['ebook'] = $ebook; $_SESSION['is-ebook-placeholder-created'] = true; diff --git a/www/ebooks/get.php b/www/ebooks/get.php index ee4ec366..431faf3e 100644 --- a/www/ebooks/get.php +++ b/www/ebooks/get.php @@ -399,19 +399,7 @@ catch(Exceptions\EbookNotFoundException){ Benefits->CanEditEbooks){ ?>
    -

    Metadata

    - - - - - - - - - - - -
    Ebook ID:EbookId ?>
    Identifier:Identifier) ?>
    + $ebook]) ?>