diff --git a/config/sql/se/Users.sql b/config/sql/se/Users.sql index 87310a17..ab40a1d5 100644 --- a/config/sql/se/Users.sql +++ b/config/sql/se/Users.sql @@ -4,6 +4,7 @@ CREATE TABLE `Users` ( `Name` varchar(255) DEFAULT NULL, `Created` datetime NOT NULL, `Uuid` char(36) NOT NULL, + `PasswordHash` varchar(255) NULL, PRIMARY KEY (`UserId`), UNIQUE KEY `idxEmail` (`Email`) ) ENGINE=InnoDB AUTO_INCREMENT=281 DEFAULT CHARSET=utf8mb4; diff --git a/lib/Artwork.php b/lib/Artwork.php index 74b1b9da..a5855794 100644 --- a/lib/Artwork.php +++ b/lib/Artwork.php @@ -17,7 +17,7 @@ use function Safe\sprintf; * @property string $ImageUrl * @property string $ThumbUrl * @property string $Thumb2xUrl - * @property string $ImageSize + * @property string $Dimensions * @property Ebook $Ebook * @property Museum $Museum * @property ?ImageMimeType $MimeType @@ -48,7 +48,7 @@ class Artwork extends PropertiesBase{ protected $_ImageUrl = null; protected $_ThumbUrl = null; protected $_Thumb2xUrl = null; - protected $_ImageSize = null; + protected $_Dimensions = null; protected $_Ebook = null; protected $_Museum = null; protected ?ImageMimeType $_MimeType = null; @@ -157,26 +157,20 @@ class Artwork extends PropertiesBase{ return $this->_Thumb2xUrl; } - protected function GetImageSize(): string{ + protected function GetDimensions(): string{ try{ - $bytes = @filesize(WEB_ROOT . $this->ImageUrl); - $sizes = 'BKMGTP'; - $factor = intval(floor((strlen((string)$bytes) - 1) / 3)); - $sizeNumber = sprintf('%.1f', $bytes / pow(1024, $factor)); - $sizeUnit = $sizes[$factor] ?? ''; - $this->_ImageSize = $sizeNumber . $sizeUnit; list($imageWidth, $imageHeight) = getimagesize(WEB_ROOT . $this->ImageUrl); if($imageWidth && $imageHeight){ - $this->_ImageSize .= ' (' . $imageWidth . ' × ' . $imageHeight . ')'; + $this->_Dimensions .= $imageWidth . ' × ' . $imageHeight; } } catch(Exception){ // Image doesn't exist - $this->_ImageSize = ''; + $this->_Dimensions = ''; } - return $this->_ImageSize; + return $this->_Dimensions; } protected function GetEbook(): ?Ebook{ @@ -217,7 +211,7 @@ class Artwork extends PropertiesBase{ $error->Add($ex); } - if(trim($this->Exception) == ''){ + if($this->Exception !== null && trim($this->Exception) == ''){ $this->Exception = null; } @@ -517,11 +511,6 @@ class Artwork extends PropertiesBase{ return false; } - public function HasMatchingMuseum(): bool{ - - return true; - } - // *********** // ORM METHODS // *********** diff --git a/lib/Core.php b/lib/Core.php index 5557b660..e0085e21 100644 --- a/lib/Core.php +++ b/lib/Core.php @@ -38,7 +38,14 @@ if($GLOBALS['User'] === null){ $session = new Session(); try{ - $session->Create($httpBasicAuthLogin); + $password = $_SERVER['PHP_AUTH_PW'] ?? null; + if($password == ''){ + $password = null; + } + + // Most patrons have a null password, meaning they only need to log in using an email and a blank password. + // Some users with admin rights need a password to log in. + $session->Create($httpBasicAuthLogin, $password); $GLOBALS['User'] = $session->User; } catch(Exception){ diff --git a/lib/Exceptions/InvalidUserException.php b/lib/Exceptions/InvalidUserException.php index 380f433c..36818da3 100644 --- a/lib/Exceptions/InvalidUserException.php +++ b/lib/Exceptions/InvalidUserException.php @@ -2,5 +2,5 @@ namespace Exceptions; class InvalidUserException extends AppException{ - protected $message = 'We couldn’t locate you in our system.'; + protected $message = 'We couldn’t validate your login information.'; } diff --git a/lib/Exceptions/PasswordRequiredException.php b/lib/Exceptions/PasswordRequiredException.php new file mode 100644 index 00000000..daf0d8f7 --- /dev/null +++ b/lib/Exceptions/PasswordRequiredException.php @@ -0,0 +1,5 @@ +User = User::GetIfRegistered($email); + public function Create(?string $email = null, ?string $password = null): void{ + $this->User = User::GetIfRegistered($email, $password); $this->UserId = $this->User->UserId; $existingSessions = Db::Query(' @@ -59,7 +59,7 @@ class Session extends PropertiesBase{ ', [$this->UserId, $this->SessionId, $this->Created]); } - $this->SetSessionCookie($this->SessionId); + self::SetSessionCookie($this->SessionId); } public static function GetLoggedInUser(): ?User{ diff --git a/lib/User.php b/lib/User.php index cffe7959..060ba8a6 100644 --- a/lib/User.php +++ b/lib/User.php @@ -12,6 +12,7 @@ class User extends PropertiesBase{ public $Email; public $Created; public $Uuid; + public $PasswordHash; protected $_IsRegistered = null; protected $_Payments = null; protected $_Benefits = null; @@ -73,19 +74,25 @@ class User extends PropertiesBase{ // METHODS // ******* - public function Create(): void{ + public function Create(?string $password = null): void{ $uuid = Uuid::uuid4(); $this->Uuid = $uuid->toString(); $this->Created = new DateTime(); + $this->PasswordHash = null; + if($password !== null){ + $this->PasswordHash = password_hash($password, PASSWORD_DEFAULT); + } + try{ Db::Query(' - INSERT into Users (Email, Name, Uuid, Created) + INSERT into Users (Email, Name, Uuid, Created, PasswordHash) values (?, + ?, ?, ?, ?) - ', [$this->Email, $this->Name, $this->Uuid, $this->Created]); + ', [$this->Email, $this->Name, $this->Uuid, $this->Created, $this->PasswordHash]); } catch(PDOException $ex){ if(($ex->errorInfo[1] ?? 0) == 1062){ @@ -137,7 +144,7 @@ class User extends PropertiesBase{ return $result[0]; } - public static function GetIfRegistered(?string $identifier): User{ + public static function GetIfRegistered(?string $identifier, ?string $password = null): User{ // We consider a user "registered" if they have a row in the Benefits table. // Emails without that row may only be signed up for the newsletter and thus are not "registered" users // The identifier is either an email or a UUID (api key) @@ -157,6 +164,15 @@ class User extends PropertiesBase{ throw new Exceptions\InvalidUserException(); } + if($result[0]->PasswordHash !== null && $password === null){ + // Indicate that a password is required before we log in + throw new Exceptions\PasswordRequiredException(); + } + + if($result[0]->PasswordHash !== null && !password_verify($password ?? '', $result[0]->PasswordHash)){ + throw new Exceptions\InvalidUserException(); + } + return $result[0]; } } diff --git a/scripts/upsert-to-cover-art-database b/scripts/upsert-to-cover-art-database index beb85062..9a3f7b5f 100755 --- a/scripts/upsert-to-cover-art-database +++ b/scripts/upsert-to-cover-art-database @@ -112,6 +112,7 @@ if($artwork === null){ } $artwork = new Artwork(); + $artwork->Artist = new Artist(); $artwork->Artist = $artist; $artwork->Name = $artworkName; $artwork->CompletedYear = $completedYear; diff --git a/templates/ArtworkDetail.php b/templates/ArtworkDetail.php index ec0233ee..4afe4efa 100644 --- a/templates/ArtworkDetail.php +++ b/templates/ArtworkDetail.php @@ -1,5 +1,6 @@ - + + +

Metadata

- + - + - - - - - - + + @@ -70,9 +69,8 @@ if($artwork === null){

Page scans

diff --git a/templates/ArtworkList.php b/templates/ArtworkList.php index eccc8cec..58347f70 100644 --- a/templates/ArtworkList.php +++ b/templates/ArtworkList.php @@ -10,7 +10,7 @@ $useAdminUrl = $useAdminUrl ?? false; Url; ?> -
  • +
  • @@ -25,8 +25,8 @@ $useAdminUrl = $useAdminUrl ?? false; Artist->AlternateSpellings) > 0){ ?>(AKA , ', array_map('Formatter::ToPlainText', $artwork->Artist->AlternateSpellings)) ?>)

    -

    Year completed: CompletedYear === null){ ?>(unknown)CompletedYear ?>CompletedYearIsCirca){ ?> (circa)

    -

    Status: $artwork]) ?>

    +

    Year completed: CompletedYear === null){ ?>UnknownCompletedYearIsCirca){ ?>CircaCompletedYear ?>

    + Status == COVER_ARTWORK_STATUS_IN_USE){ ?>

    Status: $artwork]) ?>

    Tags) > 0){ ?>

    Tags:

    diff --git a/templates/ArtworkSearchForm.php b/templates/ArtworkSearchForm.php index ac574ca4..571f61f0 100644 --- a/templates/ArtworkSearchForm.php +++ b/templates/ArtworkSearchForm.php @@ -1,7 +1,7 @@ diff --git a/templates/ArtworkStatus.php b/templates/ArtworkStatus.php index b29bcc03..d2989e46 100644 --- a/templates/ArtworkStatus.php +++ b/templates/ArtworkStatus.php @@ -1,10 +1,9 @@ Status === COVER_ARTWORK_STATUS_APPROVED){ ?>Approved Status === COVER_ARTWORK_STATUS_DECLINED){ ?>Declined Status === COVER_ARTWORK_STATUS_UNVERIFIED){ ?>Unverified -Status === COVER_ARTWORK_STATUS_IN_USE){ ?>In useEbook !== null && $artwork->Ebook->Url !== null){ ?> by Ebook->Title) ?> +Status === COVER_ARTWORK_STATUS_IN_USE){ ?>In useEbook !== null && $artwork->Ebook->Url !== null){ ?> for Ebook->Title) ?> diff --git a/templates/ImageCopyrightNotice.php b/templates/ImageCopyrightNotice.php index 31947a96..b3324dd6 100644 --- a/templates/ImageCopyrightNotice.php +++ b/templates/ImageCopyrightNotice.php @@ -1 +1 @@ -

    These images are thought to be free of copyright restrictions in the United States. They may still be under copyright in other countries. If you’re not located in the United States, you must check your local laws to verify that these images are free of copyright restrictions in the country you’re located in before accessing, downloading, or using them.

    +

    Careful research leads Standard Ebooks to believe that these images are free of copyright restrictions in the United States. You must do your own research to confirm their copyright status before using them. They may also still be under copyright in other countries. If you’re not located in the United States, you must check your local laws to verify that these images are free of copyright restrictions in the country you’re located in before accessing, downloading, or using them.

    diff --git a/www/admin/artworks/get.php b/www/admin/artworks/get.php index b1c91458..e83bf9e1 100644 --- a/www/admin/artworks/get.php +++ b/www/admin/artworks/get.php @@ -29,7 +29,7 @@ catch(Exceptions\AppException){
    $exception]) ?>
    - $artwork]) ?> + $artwork, 'showCopyrightNotice' => false]) ?> Status == COVER_ARTWORK_STATUS_DECLINED){ ?>

    Status

    This artwork has been declined by a reviewer.

    diff --git a/www/artworks/index.php b/www/artworks/index.php index 27bb5767..ad4d7559 100644 --- a/www/artworks/index.php +++ b/www/artworks/index.php @@ -58,13 +58,11 @@ if($perPage !== COVER_ARTWORK_PER_PAGE){ $queryString .= '&per-page=' . urlencode((string)$perPage); } - -$queryString = preg_replace('/^&/ius', '', $queryString); ?> $pageTitle, 'artwork' => true, 'description' => $pageDescription]) ?>

    Browse U.S. Public Domain Artwork

    - +

    You can help Standard Ebooks by submitting new public domain artwork to add to this catalog for use in future ebooks. For free access to the submission form, contact the Editor-in-Chief.

    $query, 'status' => $status, 'sort' => $sort, 'perPage' => $perPage]) ?> @@ -74,13 +72,13 @@ $queryString = preg_replace('/^&/ius', '', $queryString); 0){ ?>
    diff --git a/www/artworks/new.php b/www/artworks/new.php index 7fac2590..4903dced 100644 --- a/www/artworks/new.php +++ b/www/artworks/new.php @@ -74,7 +74,7 @@ catch(Exceptions\InvalidPermissionsException){ For existing artists, leave the year of death blank. - +
  • TitleName) ?>Name) ?>
    Artist - Artist->Name) ?>Artist->AlternateSpellings) > 0){ ?> (AKA , ', array_map('Formatter::ToPlainText', $artwork->Artist->AlternateSpellings)) ?>)Artist->DeathYear !== null){ ?>, d. Artist->DeathYear ?> + Artist->Name) ?>Artist->AlternateSpellings) > 0){ ?> (AKA , ', array_map('Formatter::ToPlainText', $artwork->Artist->AlternateSpellings)) ?>)Artist->DeathYear !== null){ ?> (d. Artist->DeathYear ?>)
    Year completedCompletedYear === null){ ?>(unknown)CompletedYear ?>CompletedYearIsCirca){ ?> (circa)CompletedYear === null){ ?>UnknownCompletedYearIsCirca){ ?>Circa CompletedYear ?>
    File sizeImageSize ?>
    UploadedCreated->format('F j, Y g:i a') ?>DimensionsDimensions ?>
    Status