mirror of
https://github.com/standardebooks/web.git
synced 2025-07-06 06:40:33 -04:00
Add projects index page, and more detail on placeholder pages
This commit is contained in:
parent
fe5bb8ed48
commit
c7a4e34e31
15 changed files with 211 additions and 59 deletions
|
@ -12,6 +12,7 @@ CREATE TABLE IF NOT EXISTS `Benefits` (
|
||||||
`CanCreateEbookPlaceholders` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
`CanCreateEbookPlaceholders` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
`CanManageProjects` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
`CanManageProjects` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
`CanReviewProjects` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
`CanReviewProjects` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`CanEditProjects` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
PRIMARY KEY (`UserId`),
|
PRIMARY KEY (`UserId`),
|
||||||
KEY `idxBenefits` (`CanAccessFeeds`,`CanVote`,`CanBulkDownload`)
|
KEY `idxBenefits` (`CanAccessFeeds`,`CanVote`,`CanBulkDownload`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
|
@ -18,6 +18,9 @@ class Benefits{
|
||||||
public bool $CanEditCollections = false;
|
public bool $CanEditCollections = false;
|
||||||
public bool $CanEditEbooks = false;
|
public bool $CanEditEbooks = false;
|
||||||
public bool $CanCreateEbookPlaceholders = false;
|
public bool $CanCreateEbookPlaceholders = false;
|
||||||
|
public bool $CanManageProjects = false;
|
||||||
|
public bool $CanReviewProjects = false;
|
||||||
|
public bool $CanEditProjects = false;
|
||||||
|
|
||||||
protected bool $_HasBenefits;
|
protected bool $_HasBenefits;
|
||||||
|
|
||||||
|
@ -36,6 +39,12 @@ class Benefits{
|
||||||
$this->CanEditEbooks
|
$this->CanEditEbooks
|
||||||
||
|
||
|
||||||
$this->CanCreateEbookPlaceholders
|
$this->CanCreateEbookPlaceholders
|
||||||
|
||
|
||||||
|
$this->CanManageProjects
|
||||||
|
||
|
||||||
|
$this->CanReviewProjects
|
||||||
|
||
|
||||||
|
$this->CanEditProjects
|
||||||
){
|
){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1028,6 +1028,17 @@ class Ebook{
|
||||||
return $ebook;
|
return $ebook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\EbookNotFoundException If the `Ebook` can't be found.
|
||||||
|
*/
|
||||||
|
public static function Get(?int $ebookId): Ebook{
|
||||||
|
if($ebookId === null){
|
||||||
|
throw new Exceptions\EbookNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Db::Query('SELECT * from Ebooks where EbookId = ?', [$ebookId], Ebook::class)[0] ?? throw new Exceptions\EbookNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Joins the `Name` properites of `Contributor` objects as a URL slug, e.g.,
|
* Joins the `Name` properites of `Contributor` objects as a URL slug, e.g.,
|
||||||
*
|
*
|
||||||
|
|
|
@ -22,4 +22,7 @@ enum DateTimeFormat: string{
|
||||||
|
|
||||||
/** Like `1641426132`. */
|
/** Like `1641426132`. */
|
||||||
case UnixTimestamp = 'U';
|
case UnixTimestamp = 'U';
|
||||||
|
|
||||||
|
/** Like Jan 5, 2024 */
|
||||||
|
case ShortDate = 'M j, Y';
|
||||||
}
|
}
|
||||||
|
|
7
lib/Exceptions/ProjectNotFoundException.php
Normal file
7
lib/Exceptions/ProjectNotFoundException.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?
|
||||||
|
namespace Exceptions;
|
||||||
|
|
||||||
|
class ProjectNotFoundException extends AppException{
|
||||||
|
/** @var string $message */
|
||||||
|
protected $message = 'We couldn’t locate that project.';
|
||||||
|
}
|
|
@ -62,7 +62,7 @@ class Library{
|
||||||
// Add a period to the abbreviated month, but not if it's May (the only 3-letter month)
|
// Add a period to the abbreviated month, but not if it's May (the only 3-letter month)
|
||||||
$obj->UpdatedString = preg_replace('/^(.+?)(?<!May) /', '\1. ', $obj->UpdatedString);
|
$obj->UpdatedString = preg_replace('/^(.+?)(?<!May) /', '\1. ', $obj->UpdatedString);
|
||||||
if($obj->Updated->format('Y') != NOW->format('Y')){
|
if($obj->Updated->format('Y') != NOW->format('Y')){
|
||||||
$obj->UpdatedString = $obj->Updated->format('M j, Y');
|
$obj->UpdatedString = $obj->Updated->format(Enums\DateTimeFormat::ShortDate->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the downloads by filename extension
|
// Sort the downloads by filename extension
|
||||||
|
|
|
@ -31,6 +31,11 @@ class Project{
|
||||||
protected User $_ReviewerUser;
|
protected User $_ReviewerUser;
|
||||||
protected string $_Url;
|
protected string $_Url;
|
||||||
|
|
||||||
|
|
||||||
|
// *******
|
||||||
|
// GETTERS
|
||||||
|
// *******
|
||||||
|
|
||||||
protected function GetUrl(): string{
|
protected function GetUrl(): string{
|
||||||
if(!isset($this->_Url)){
|
if(!isset($this->_Url)){
|
||||||
$this->_Url = '/projects/' . $this->ProjectId;
|
$this->_Url = '/projects/' . $this->ProjectId;
|
||||||
|
@ -39,6 +44,11 @@ class Project{
|
||||||
return $this->_Url;
|
return $this->_Url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *******
|
||||||
|
// METHODS
|
||||||
|
// *******
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exceptions\InvalidProjectException If the `Project` is invalid.
|
* @throws Exceptions\InvalidProjectException If the `Project` is invalid.
|
||||||
*/
|
*/
|
||||||
|
@ -218,4 +228,27 @@ class Project{
|
||||||
$this->PropertyFromHttp('ManagerUserId');
|
$this->PropertyFromHttp('ManagerUserId');
|
||||||
$this->PropertyFromHttp('ReviewerUserId');
|
$this->PropertyFromHttp('ReviewerUserId');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ***********
|
||||||
|
// ORM METHODS
|
||||||
|
// ***********
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exceptions\ProjectNotFoundException If the `Project` can't be found.
|
||||||
|
*/
|
||||||
|
public static function Get(?int $projectId): Project{
|
||||||
|
if($projectId === null){
|
||||||
|
throw new Exceptions\ProjectNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Db::Query('SELECT * from Projects where ProjectId = ?', [$projectId], Project::class)[0] ?? throw new Exceptions\ProjectNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<Project>
|
||||||
|
*/
|
||||||
|
public static function GetAllByStatus(Enums\ProjectStatusType $status): array{
|
||||||
|
return Db::Query('SELECT * from Projects where Status = ? order by Started desc', [$status], Project::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* @var array<stdClass> $collections
|
* @var array<stdClass> $collections
|
||||||
*/
|
*/
|
||||||
?>
|
?>
|
||||||
<table class="download-list">
|
<table class="data-table bulk-downloads-table">
|
||||||
<caption aria-hidden="hidden">Scroll right →</caption>
|
<caption aria-hidden="hidden">Scroll right →</caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="mid-header">
|
<tr class="mid-header">
|
||||||
|
|
|
@ -10,10 +10,6 @@
|
||||||
<td>Ebook ID:</td>
|
<td>Ebook ID:</td>
|
||||||
<td><?= $ebook->EbookId ?></td>
|
<td><?= $ebook->EbookId ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>Identifier:</td>
|
|
||||||
<td><?= Formatter::EscapeHtml($ebook->Identifier) ?></td>
|
|
||||||
</tr>
|
|
||||||
<? if($ebook->IsPlaceholder() && $ebook->EbookPlaceholder !== null){ ?>
|
<? if($ebook->IsPlaceholder() && $ebook->EbookPlaceholder !== null){ ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Is wanted:</td>
|
<td>Is wanted:</td>
|
||||||
|
@ -27,24 +23,13 @@
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Difficulty:</td>
|
<td>Difficulty:</td>
|
||||||
<td><?= ucfirst($ebook->EbookPlaceholder->Difficulty->value) ?></td>
|
<td><?= ucfirst($ebook->EbookPlaceholder->Difficulty->value ?? '') ?></td>
|
||||||
</tr>
|
|
||||||
<? } ?>
|
|
||||||
<? if(sizeof($ebook->Projects) > 0){ ?>
|
|
||||||
<tr>
|
|
||||||
<td>Projects:</td>
|
|
||||||
<td>
|
|
||||||
<ul>
|
|
||||||
<? foreach($ebook->Projects as $project){ ?>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
<?= $project->Started->format(Enums\DateTimeFormat::FullDateTime->value) ?> — <?= $project->Status->GetDisplayName() ?> — <? if($project->ProducerEmail !== null){ ?><a href="mailto:<?= Formatter::EscapeHtml($project->ProducerEmail) ?>"><?= Formatter::EscapeHtml($project->ProducerName) ?></a><? }else{ ?><?= Formatter::EscapeHtml($project->ProducerName) ?><? } ?> — <a href="<?= $project->Url ?>">Link</a>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<? } ?>
|
|
||||||
</ul>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<? if(sizeof($ebook->Projects) > 0){ ?>
|
||||||
|
<h2>Projects</h2>
|
||||||
|
<?= Template::ProjectsTable(['projects' => $ebook->Projects, 'includeTitle' => false]) ?>
|
||||||
|
<? } ?>
|
||||||
|
|
48
templates/ProjectsTable.php
Normal file
48
templates/ProjectsTable.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?
|
||||||
|
/**
|
||||||
|
* @var array<Project> $projects
|
||||||
|
*/
|
||||||
|
|
||||||
|
$includeTitle = $includeTitle ?? true;
|
||||||
|
?>
|
||||||
|
<table class="data-table">
|
||||||
|
<caption aria-hidden="hidden">Scroll right →</caption>
|
||||||
|
<thead>
|
||||||
|
<tr class="mid-header">
|
||||||
|
<? if($includeTitle){ ?>
|
||||||
|
<th scope="col">Title</th>
|
||||||
|
<? } ?>
|
||||||
|
<th scope="col">Started</th>
|
||||||
|
<th scope="col">Producer</th>
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<th/>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<? foreach($projects as $project){ ?>
|
||||||
|
<tr>
|
||||||
|
<? if($includeTitle){ ?>
|
||||||
|
<td class="row-header">
|
||||||
|
<a href="<?= $project->Ebook->Url ?>"><?= Formatter::EscapeHtml($project->Ebook->Title) ?></a>
|
||||||
|
</td>
|
||||||
|
<? } ?>
|
||||||
|
<td>
|
||||||
|
<?= $project->Started->format(Enums\DateTimeFormat::ShortDate->value) ?>
|
||||||
|
</td>
|
||||||
|
<td class="producer">
|
||||||
|
<? if($project->ProducerEmail !== null){ ?>
|
||||||
|
<a href="mailto:<?= Formatter::EscapeHtml($project->ProducerEmail) ?>"><?= Formatter::EscapeHtml($project->ProducerName) ?></a>
|
||||||
|
<? }else{ ?>
|
||||||
|
<?= Formatter::EscapeHtml($project->ProducerName) ?>
|
||||||
|
<? } ?>
|
||||||
|
</td>
|
||||||
|
<td class="status">
|
||||||
|
<?= ucfirst($project->Status->GetDisplayName()) ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="<?= Formatter::EscapeHtml($project->VcsUrl) ?>">GitHub repo</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<? } ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -36,7 +36,7 @@ $title = preg_replace('/s$/', '', ucfirst($class));
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<p>These zip files contain each ebook in every format we offer, and are kept updated with the latest versions of each ebook. Read about <a href="/help/how-to-use-our-ebooks#which-file-to-download">which file format to download</a>.</p>
|
<p>These zip files contain each ebook in every format we offer, and are kept updated with the latest versions of each ebook. Read about <a href="/help/how-to-use-our-ebooks#which-file-to-download">which file format to download</a>.</p>
|
||||||
<? if($class == 'months'){ ?>
|
<? if($class == 'months'){ ?>
|
||||||
<table class="download-list">
|
<table class="data-table">
|
||||||
<caption aria-hidden="hidden">Scroll right →</caption>
|
<caption aria-hidden="hidden">Scroll right →</caption>
|
||||||
<tbody>
|
<tbody>
|
||||||
<? foreach($collection as $year => $months){ ?>
|
<? foreach($collection as $year => $months){ ?>
|
||||||
|
|
|
@ -731,90 +731,93 @@ ul.message.error > li + li{
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list{
|
.data-table{
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list caption{
|
.data-table caption{
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list .mid-header{
|
.data-table .mid-header{
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list thead tr.mid-header:first-child > *{
|
.data-table thead tr.mid-header:first-child > *{
|
||||||
padding-top: 2rem;
|
padding-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list th.row-header,
|
.data-table td,
|
||||||
.download-list .mid-header th:first-child,
|
.data-table th{
|
||||||
.download-list .mid-header th:last-child{
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.download-list td,
|
|
||||||
.download-list th{
|
|
||||||
padding: .25rem .5rem;
|
padding: .25rem .5rem;
|
||||||
hyphens: none;
|
hyphens: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list th{
|
.data-table th{
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table.bulk-downloads-table th.row-header,
|
||||||
|
.data-table.bulk-downloads-table .mid-header th:first-child,
|
||||||
|
.data-table.bulk-downloads-table .mid-header th:last-child{
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table.bulk-downloads-table th{
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list .number{
|
.data-table .number{
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list td.download{
|
.data-table td.download{
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
color: var(--body-text);
|
color: var(--body-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list td.download + td{
|
.data-table td.download + td{
|
||||||
padding-left: .25rem;
|
padding-left: .25rem;
|
||||||
font-size: .75em;
|
font-size: .75em;
|
||||||
color: var(--sub-text);
|
color: var(--sub-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list tbody .row-header{
|
.data-table tbody .row-header{
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list tbody tr td,
|
.data-table tbody tr td,
|
||||||
.download-list tbody tr th{
|
.data-table tbody tr th{
|
||||||
border-top: 1px dashed var(--table-border);
|
border-top: 1px dashed var(--table-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list tbody tr:first-child > *,
|
.data-table tbody tr:first-child > *,
|
||||||
.download-list tbody tr.year-header > *,
|
.data-table tbody tr.year-header > *,
|
||||||
.download-list tbody tr.year-header + tr > *,
|
.data-table tbody tr.year-header + tr > *,
|
||||||
.download-list tbody tr.mid-header tr > *,
|
.data-table tbody tr.mid-header tr > *,
|
||||||
.download-list tbody tr.mid-header + tr td,
|
.data-table tbody tr.mid-header + tr td,
|
||||||
.download-list tbody tr.mid-header + tr th{
|
.data-table tbody tr.mid-header + tr th{
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list tbody tr:not([class]):hover > *{
|
.data-table tbody tr:not([class]):hover > *{
|
||||||
background: var(--table-row-hover);
|
background: var(--table-row-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list tbody tr:only-child:not([class]):hover > *{
|
.data-table tbody tr:only-child:not([class]):hover > *{
|
||||||
background: unset; /* Don't highlight on hover if there's only one row */
|
background: unset; /* Don't highlight on hover if there's only one row */
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 + .download-list tr.year-header:first-child th{
|
h2 + .data-table tr.year-header:first-child th{
|
||||||
padding-top: 2rem;
|
padding-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list .year-header th{
|
.data-table .year-header th{
|
||||||
padding-top: 4rem;
|
padding-top: 4rem;
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
font-family: "League Spartan", Arial, sans-serif;
|
font-family: "League Spartan", Arial, sans-serif;
|
||||||
|
@ -3327,23 +3330,23 @@ table.admin-table td + td{
|
||||||
}
|
}
|
||||||
|
|
||||||
@media(max-width: 1200px){
|
@media(max-width: 1200px){
|
||||||
.download-list{
|
.data-table{
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
display: block; /* needed to make overflow work */
|
display: block; /* needed to make overflow work */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list .year-header th{
|
.data-table .year-header th{
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.download-list thead tr.mid-header:first-child th,
|
.data-table thead tr.mid-header:first-child th,
|
||||||
.download-list tr.year-header:first-child th{
|
.data-table tr.year-header:first-child th{
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-list caption{
|
.data-table caption{
|
||||||
display: block;
|
display: block;
|
||||||
padding-top: 2rem;
|
padding-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,3 +11,16 @@
|
||||||
.project-form label:has(input[name="project-manager-user-id"]){
|
.project-form label:has(input[name="project-manager-user-id"]){
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2 + table.projects{
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.projects thead{
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.data-table .status,
|
||||||
|
table.data-table .producer{
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
|
@ -283,7 +283,7 @@ catch(Exceptions\EbookNotFoundException){
|
||||||
<ol>
|
<ol>
|
||||||
<? foreach($ebook->GitCommits as $commit){ ?>
|
<? foreach($ebook->GitCommits as $commit){ ?>
|
||||||
<li>
|
<li>
|
||||||
<time datetime="<?= $commit->Created->format(DateTimeImmutable::RFC3339) ?>"><?= $commit->Created->format('M j, Y') ?></time>
|
<time datetime="<?= $commit->Created->format(DateTimeImmutable::RFC3339) ?>"><?= $commit->Created->format(Enums\DateTimeFormat::ShortDate->value) ?></time>
|
||||||
<p>
|
<p>
|
||||||
<a href="<?= Formatter::EscapeHtml($ebook->GitHubUrl) ?>/commit/<?= Formatter::EscapeHtml($commit->Hash) ?>"><?= Formatter::EscapeHtml($commit->Message) ?></a>
|
<a href="<?= Formatter::EscapeHtml($ebook->GitHubUrl) ?>/commit/<?= Formatter::EscapeHtml($commit->Hash) ?>"><?= Formatter::EscapeHtml($commit->Message) ?></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
39
www/projects/index.php
Normal file
39
www/projects/index.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?
|
||||||
|
try{
|
||||||
|
if(Session::$User === null){
|
||||||
|
throw new Exceptions\LoginRequiredException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Session::$User->Benefits->CanEditProjects){
|
||||||
|
throw new Exceptions\InvalidPermissionsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$inProgressProjects = Project::GetAllByStatus(Enums\ProjectStatusType::InProgress);
|
||||||
|
$stalledProjects = Project::GetAllByStatus(Enums\ProjectStatusType::Stalled);
|
||||||
|
}
|
||||||
|
catch(Exceptions\LoginRequiredException){
|
||||||
|
Template::RedirectToLogin();
|
||||||
|
}
|
||||||
|
catch(Exceptions\InvalidPermissionsException){
|
||||||
|
Template::Emit403();
|
||||||
|
}
|
||||||
|
?><?= Template::Header(['title' => 'Projects', 'css' => ['/css/project.css'], 'description' => 'Ebook projects currently underway at Standard Ebooks.']) ?>
|
||||||
|
<main>
|
||||||
|
<section class="narrow">
|
||||||
|
<h1>Projects</h1>
|
||||||
|
<h2>Active projects</h2>
|
||||||
|
<? if(sizeof($inProgressProjects) == 0){ ?>
|
||||||
|
<p>
|
||||||
|
<i>None.</i>
|
||||||
|
</p>
|
||||||
|
<? }else{ ?>
|
||||||
|
<?= Template::ProjectsTable(['projects' => $inProgressProjects]) ?>
|
||||||
|
<? } ?>
|
||||||
|
|
||||||
|
<? if(sizeof($stalledProjects) > 0){ ?>
|
||||||
|
<h2>Stalled projects</h2>
|
||||||
|
<?= Template::ProjectsTable(['projects' => $stalledProjects]) ?>
|
||||||
|
<? } ?>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<?= Template::Footer() ?>
|
Loading…
Add table
Add a link
Reference in a new issue