Use a NOW constant instead of new DateTimeImmutable objects, and tweak how some donation drive dates work

This commit is contained in:
Alex Cabal 2024-10-15 22:21:12 -05:00
parent 376dacd833
commit eec79712fc
27 changed files with 108 additions and 143 deletions

View file

@ -87,9 +87,7 @@ class Artist{
* @throws Exceptions\InvalidArtistException * @throws Exceptions\InvalidArtistException
*/ */
public function Validate(): void{ public function Validate(): void{
/** @throws void */ $thisYear = intval(NOW->format('Y'));
$now = new DateTimeImmutable();
$thisYear = intval($now->format('Y'));
$error = new Exceptions\InvalidArtistException(); $error = new Exceptions\InvalidArtistException();

View file

@ -330,9 +330,7 @@ class Artwork{
* @throws Exceptions\InvalidArtworkException * @throws Exceptions\InvalidArtworkException
*/ */
protected function Validate(?string $imagePath = null, bool $isImageRequired = true): void{ protected function Validate(?string $imagePath = null, bool $isImageRequired = true): void{
/** @throws void */ $thisYear = intval(NOW->format('Y'));
$now = new DateTimeImmutable();
$thisYear = intval($now->format('Y'));
$error = new Exceptions\InvalidArtworkException(); $error = new Exceptions\InvalidArtworkException();
if($this->Artist === null){ if($this->Artist === null){
@ -664,8 +662,7 @@ class Artwork{
$this->Validate($imagePath, true); $this->Validate($imagePath, true);
/** @throws void */ $this->Created = NOW;
$this->Created = new DateTimeImmutable();
$tags = []; $tags = [];
foreach($this->Tags as $artworkTag){ foreach($this->Tags as $artworkTag){
@ -731,10 +728,8 @@ class Artwork{
if($imagePath !== null){ if($imagePath !== null){
$this->MimeType = ImageMimeType::FromFile($imagePath); $this->MimeType = ImageMimeType::FromFile($imagePath);
// Manually set the updated timestamp, because if we only update the image and nothing else, the row's // Manually set the updated timestamp, because if we only update the image and nothing else, the row's updated timestamp won't change automatically.
// updated timestamp won't change automatically. $this->Updated = NOW;
/** @throws void */
$this->Updated = new DateTimeImmutable();
$this->_ImageUrl = null; $this->_ImageUrl = null;
$this->_ThumbUrl = null; $this->_ThumbUrl = null;
$this->_Thumb2xUrl = null; $this->_Thumb2xUrl = null;
@ -751,12 +746,12 @@ class Artwork{
$newDeathYear = $this->Artist->DeathYear; $newDeathYear = $this->Artist->DeathYear;
$this->Artist = Artist::GetOrCreate($this->Artist); $this->Artist = Artist::GetOrCreate($this->Artist);
// Save the artist death year in case we changed it // Save the artist death year in case we changed it.
if($newDeathYear != $this->Artist->DeathYear){ if($newDeathYear != $this->Artist->DeathYear){
Db::Query('UPDATE Artists set DeathYear = ? where ArtistId = ?', [$newDeathYear , $this->Artist->ArtistId]); Db::Query('UPDATE Artists set DeathYear = ? where ArtistId = ?', [$newDeathYear , $this->Artist->ArtistId]);
} }
// Save the artwork // Save the artwork.
Db::Query(' Db::Query('
UPDATE Artworks UPDATE Artworks
set set
@ -787,9 +782,8 @@ class Artwork{
$this->ArtworkId] $this->ArtworkId]
); );
// Delete artists who are no longer to attached to an artwork // Delete artists who are no longer to attached to an artwork.
// Don't delete from the ArtistAlternateNames table to prevent accidentally // Don't delete from the ArtistAlternateNames table to prevent accidentally deleting those manually-added entries.
// deleting those manually-added entries.
Db::Query(' Db::Query('
DELETE DELETE
from Artists from Artists
@ -797,7 +791,7 @@ class Artwork{
(select distinct ArtistId from Artworks) (select distinct ArtistId from Artworks)
'); ');
// Update tags for this artwork // Update tags for this artwork.
Db::Query(' Db::Query('
DELETE from ArtworkTags DELETE from ArtworkTags
where where

View file

@ -39,8 +39,7 @@ class AtomFeed extends Feed{
// Did we actually update the feed? If so, write to file and update the index // Did we actually update the feed? If so, write to file and update the index
if($this->HasChanged($this->Path)){ if($this->HasChanged($this->Path)){
// Files don't match, save the file // Files don't match, save the file
/** @throws void */ $this->Updated = NOW;
$this->Updated = new DateTimeImmutable();
$this->Save(); $this->Save();
return true; return true;
} }

View file

@ -1,15 +1,14 @@
<? <?
// Auto-included by Composer in composer.json to satisfy PHPStan // Auto-included by Composer in composer.json to satisfy PHPStan.
use Safe\DateTimeImmutable; use Safe\DateTimeImmutable;
use function Safe\define; use function Safe\define;
$now = new DateTimeImmutable(); const NOW = new DateTimeImmutable();
$nowPd = new DateTimeImmutable('now', new DateTimeZone('America/Juneau')); // Latest continental US time zone
const SITE_STATUS_LIVE = 'live'; const SITE_STATUS_LIVE = 'live';
const SITE_STATUS_DEV = 'dev'; const SITE_STATUS_DEV = 'dev';
define('SITE_STATUS', get_cfg_var('app.site_status') ?: SITE_STATUS_DEV); // Set in the PHP INI configuration for both CLI and FPM. Have to use define() and not const so we can use a function. define('SITE_STATUS', get_cfg_var('app.site_status') ?: SITE_STATUS_DEV); // Set in the PHP INI configuration for both CLI and FPM. Have to use `define()` and not `const` so we can use a function.
// No trailing slash on any of the below constants. // No trailing slash on any of the below constants.
if(SITE_STATUS == SITE_STATUS_LIVE){ if(SITE_STATUS == SITE_STATUS_LIVE){
@ -44,7 +43,7 @@ const ARTWORK_IMAGE_MINIMUM_HEIGHT = 300;
const CAPTCHA_IMAGE_HEIGHT = 72; const CAPTCHA_IMAGE_HEIGHT = 72;
const CAPTCHA_IMAGE_WIDTH = 230; const CAPTCHA_IMAGE_WIDTH = 230;
// These are defined for convenience, so that getting HTTP input isn't so wordy // These are defined for convenience, so that getting HTTP input isn't so wordy.
const GET = Enums\HttpVariableSource::Get; const GET = Enums\HttpVariableSource::Get;
const POST = Enums\HttpVariableSource::Post; const POST = Enums\HttpVariableSource::Post;
const SESSION = Enums\HttpVariableSource::Session; const SESSION = Enums\HttpVariableSource::Session;
@ -72,18 +71,18 @@ const ZOHO_WEBHOOK_LOG_FILE_PATH = '/var/log/local/webhooks-zoho.log'; // Must b
const DONATIONS_LOG_FILE_PATH = '/var/log/local/donations.log'; // Must be writable by `www-data` Unix user. const DONATIONS_LOG_FILE_PATH = '/var/log/local/donations.log'; // Must be writable by `www-data` Unix user.
const ARTWORK_UPLOADS_LOG_FILE_PATH = '/var/log/local/artwork-uploads.log'; // Must be writable by `www-data` Unix user. const ARTWORK_UPLOADS_LOG_FILE_PATH = '/var/log/local/artwork-uploads.log'; // Must be writable by `www-data` Unix user.
define('PD_YEAR', intval($nowPd->format('Y')) - 96); define('PD_YEAR', intval((new DateTimeImmutable('now', new DateTimeZone('America/Juneau')))->format('Y')) - 96); // Latest continental US time zone.
define('PD_STRING', 'January 1, ' . (PD_YEAR + 1)); define('PD_STRING', 'January 1, ' . (PD_YEAR + 1));
define('DONATION_HOLIDAY_ALERT_ON', $now > new DateTimeImmutable('November 15, ' . $now->format('Y')) || $now < new DateTimeImmutable('January 7, ' . $now->add(new DateInterval('P1Y'))->format('Y'))); define('DONATION_HOLIDAY_ALERT_ON', NOW > new DateTimeImmutable('November 15, ' . NOW->format('Y')) || NOW < new DateTimeImmutable('January 7, ' . NOW->add(new DateInterval('P1Y'))->format('Y')));
define('DONATION_ALERT_ON', DONATION_HOLIDAY_ALERT_ON || rand(1, 4) == 2); define('DONATION_ALERT_ON', DONATION_HOLIDAY_ALERT_ON || rand(1, 4) == 2);
// Controls the progress bar donation dialog // Controls the progress bar donation dialog
const DONATION_DRIVE_ON = true; const DONATION_DRIVE_ON = true;
const DONATION_DRIVE_START = 'May 20, 2024 00:00:00 America/New_York'; const DONATION_DRIVE_START = new DateTimeImmutable('May 20, 2024 00:00:00 America/New_York');
const DONATION_DRIVE_END = 'June 3, 2024 23:59:00 America/New_York'; const DONATION_DRIVE_END = new DateTimeImmutable('June 3, 2024 23:59:00 America/New_York');
// Controls the countdown donation dialog // Controls the countdown donation dialog
const DONATION_DRIVE_COUNTER_ON = false; const DONATION_DRIVE_COUNTER_ON = false;
const DONATION_DRIVE_COUNTER_START = 'May 2, 2022 00:00:00 America/New_York'; const DONATION_DRIVE_COUNTER_START = new DateTimeImmutable('May 2, 2022 00:00:00 America/New_York');
const DONATION_DRIVE_COUNTER_END = 'May 8, 2022 23:59:00 America/New_York'; const DONATION_DRIVE_COUNTER_END = new DateTimeImmutable('May 8, 2022 23:59:00 America/New_York');

View file

@ -446,9 +446,6 @@ class Library{
private static function FillBulkDownloadObject(string $dir, string $downloadType, string $urlRoot): stdClass{ private static function FillBulkDownloadObject(string $dir, string $downloadType, string $urlRoot): stdClass{
$obj = new stdClass(); $obj = new stdClass();
/** @throws void */
$now = new DateTimeImmutable();
// The count of ebooks in each file is stored as a filesystem attribute // The count of ebooks in each file is stored as a filesystem attribute
$obj->EbookCount = exec('attr -g se-ebook-count ' . escapeshellarg($dir)) ?: null; $obj->EbookCount = exec('attr -g se-ebook-count ' . escapeshellarg($dir)) ?: null;
if($obj->EbookCount == null){ if($obj->EbookCount == null){
@ -499,7 +496,7 @@ class Library{
$obj->UpdatedString = $obj->Updated->format('M j'); $obj->UpdatedString = $obj->Updated->format('M j');
// 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('M j, Y');
} }

View file

@ -33,10 +33,7 @@ class Log{
return; return;
} }
/** @throws void */ fwrite($fp, NOW->format('Y-m-d H:i:s') . "\t" . $this->RequestId . "\t" . $text . "\n");
$now = new DateTimeImmutable();
fwrite($fp, $now->format('Y-m-d H:i:s') . "\t" . $this->RequestId . "\t" . $text . "\n");
fclose($fp); fclose($fp);
} }
} }

View file

@ -57,8 +57,7 @@ class NewsletterSubscription{
$this->UserId = $this->User->UserId; $this->UserId = $this->User->UserId;
/** @throws void */ $this->Created = NOW;
$this->Created = new DateTimeImmutable();
try{ try{
Db::Query(' Db::Query('

View file

@ -50,8 +50,7 @@ class OpdsFeed extends AtomFeed{
if($this->HasChanged($this->Path)){ if($this->HasChanged($this->Path)){
// Files don't match, save the file and update the parent navigation feed with the last updated timestamp // Files don't match, save the file and update the parent navigation feed with the last updated timestamp
/** @throws void */ $this->Updated = NOW;
$this->Updated = new DateTimeImmutable();
if($this->Parent !== null){ if($this->Parent !== null){
$this->Parent->SaveUpdated($this->Id, $this->Updated); $this->Parent->SaveUpdated($this->Id, $this->Updated);

View file

@ -21,8 +21,7 @@ class Patron{
// ******* // *******
public function Create(): void{ public function Create(): void{
/** @throws void */ $this->Created = NOW;
$this->Created = new DateTimeImmutable();
Db::Query(' Db::Query('
INSERT into Patrons (Created, UserId, IsAnonymous, AlternateName, IsSubscribedToEmails) INSERT into Patrons (Created, UserId, IsAnonymous, AlternateName, IsSubscribedToEmails)
values(?, values(?,

View file

@ -88,8 +88,7 @@ class Poll{
public function IsActive(): bool{ public function IsActive(): bool{
/** @throws void */ /** @throws void */
$now = new DateTimeImmutable(); if( ($this->Start !== null && $this->Start > NOW) || ($this->End !== null && $this->End < NOW)){
if( ($this->Start !== null && $this->Start > $now) || ($this->End !== null && $this->End < $now)){
return false; return false;
} }

View file

@ -24,8 +24,7 @@ class RssFeed extends Feed{
protected function GetXmlString(): string{ protected function GetXmlString(): string{
if($this->XmlString === null){ if($this->XmlString === null){
/** @throws void */ $timestamp = NOW->format('r');
$timestamp = (new DateTimeImmutable())->format('r');
$feed = Template::RssFeed(['url' => $this->Url, 'description' => $this->Description, 'title' => $this->Title, 'entries' => $this->Entries, 'updated' => $timestamp]); $feed = Template::RssFeed(['url' => $this->Url, 'description' => $this->Description, 'title' => $this->Title, 'entries' => $this->Entries, 'updated' => $timestamp]);
$this->XmlString = $this->CleanXmlString($feed); $this->XmlString = $this->CleanXmlString($feed);

View file

@ -60,8 +60,7 @@ class Session{
$uuid = Uuid::uuid4(); $uuid = Uuid::uuid4();
$this->SessionId = $uuid->toString(); $this->SessionId = $uuid->toString();
/** @throws void */ $this->Created = NOW;
$this->Created = new DateTimeImmutable();
Db::Query(' Db::Query('
INSERT into Sessions (UserId, SessionId, Created) INSERT into Sessions (UserId, SessionId, Created)
values (?, values (?,

View file

@ -85,8 +85,7 @@ class User{
$uuid = Uuid::uuid4(); $uuid = Uuid::uuid4();
$this->Uuid = $uuid->toString(); $this->Uuid = $uuid->toString();
/** @throws void */ $this->Created = NOW;
$this->Created = new DateTimeImmutable();
$this->PasswordHash = null; $this->PasswordHash = null;
if($password !== null){ if($password !== null){

View file

@ -114,15 +114,13 @@ usort($allEbooks, 'SortByUpdatedDesc');
usort($newestEbooks, function($a, $b){ return $b->Created <=> $a->Created; }); usort($newestEbooks, function($a, $b){ return $b->Created <=> $a->Created; });
$newestEbooks = array_slice($newestEbooks, 0, $ebooksPerNewestEbooksFeed); $newestEbooks = array_slice($newestEbooks, 0, $ebooksPerNewestEbooksFeed);
$now = new DateTimeImmutable();
// Create OPDS feeds. // Create OPDS feeds.
$opdsRootEntries = [ $opdsRootEntries = [
new OpdsNavigationEntry( new OpdsNavigationEntry(
'Newest Standard Ebooks', 'Newest Standard Ebooks',
'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.',
'/feeds/opds/new-releases', '/feeds/opds/new-releases',
$now, NOW,
'http://opds-spec.org/sort/new', 'http://opds-spec.org/sort/new',
'acquisition' 'acquisition'
), ),
@ -130,51 +128,51 @@ $opdsRootEntries = [
'Standard Ebooks by Subject', 'Standard Ebooks by Subject',
'Browse Standard Ebooks by subject.', 'Browse Standard Ebooks by subject.',
'/feeds/opds/subjects', '/feeds/opds/subjects',
$now, NOW,
'subsection', 'subsection',
'navigation'), 'navigation'),
new OpdsNavigationEntry( new OpdsNavigationEntry(
'Standard Ebooks by Collection', 'Standard Ebooks by Collection',
'Browse Standard Ebooks by collection.', 'Browse Standard Ebooks by collection.',
'/feeds/opds/collections', '/feeds/opds/collections',
$now, NOW,
'subsection', 'subsection',
'navigation'), 'navigation'),
new OpdsNavigationEntry( new OpdsNavigationEntry(
'Standard Ebooks by Author', 'Standard Ebooks by Author',
'Browse Standard Ebooks by author.', 'Browse Standard Ebooks by author.',
'/feeds/opds/authors', '/feeds/opds/authors',
$now, NOW,
'subsection', 'subsection',
'navigation'), 'navigation'),
new OpdsNavigationEntry( new OpdsNavigationEntry(
'All Standard Ebooks', 'All Standard Ebooks',
'All Standard Ebooks, most-recently-updated first. This is a Complete Acquisition Feed as defined in OPDS 1.2 §2.5.', 'All Standard Ebooks, most-recently-updated first. This is a Complete Acquisition Feed as defined in OPDS 1.2 §2.5.',
'/feeds/opds/all', '/feeds/opds/all',
$now, NOW,
'http://opds-spec.org/crawlable', 'http://opds-spec.org/crawlable',
'acquisition') 'acquisition')
]; ];
$opdsRoot = new OpdsNavigationFeed('Standard Ebooks', 'The Standard Ebooks catalog.', '/feeds/opds', $webRoot . '/feeds/opds/index.xml', $opdsRootEntries, null); $opdsRoot = new OpdsNavigationFeed('Standard Ebooks', 'The Standard Ebooks catalog.', '/feeds/opds', $webRoot . '/feeds/opds/index.xml', $opdsRootEntries, null);
SaveFeed($opdsRoot, $force, null, null, $now); SaveFeed($opdsRoot, $force, null, null, NOW);
// Create the Subjects feeds. // Create the Subjects feeds.
CreateOpdsCollectionFeed('subject', '/feeds/opds/subjects', 'Standard Ebooks in the “%s” subject, most-recently-released first.', $subjects, $ebooksBySubject, $now, $webRoot, $opdsRoot, $force); CreateOpdsCollectionFeed('subject', '/feeds/opds/subjects', 'Standard Ebooks in the “%s” subject, most-recently-released first.', $subjects, $ebooksBySubject, NOW, $webRoot, $opdsRoot, $force);
// Create the Collections feeds. // Create the Collections feeds.
CreateOpdsCollectionFeed('collection', '/feeds/opds/collections', 'Standard Ebooks in the “%s” collection, most-recently-released first.', $collections, $ebooksByCollection, $now, $webRoot, $opdsRoot, $force); CreateOpdsCollectionFeed('collection', '/feeds/opds/collections', 'Standard Ebooks in the “%s” collection, most-recently-released first.', $collections, $ebooksByCollection, NOW, $webRoot, $opdsRoot, $force);
// Create the Author feeds. // Create the Author feeds.
CreateOpdsCollectionFeed('author', '/feeds/opds/authors', 'Standard Ebooks by %s, most-recently-released first.', $authors, $ebooksByAuthor, $now, $webRoot, $opdsRoot, $force); CreateOpdsCollectionFeed('author', '/feeds/opds/authors', 'Standard Ebooks by %s, most-recently-released first.', $authors, $ebooksByAuthor, NOW, $webRoot, $opdsRoot, $force);
// Create the All feed. // Create the All feed.
$allFeed = new OpdsAcquisitionFeed('All Standard Ebooks', 'All Standard Ebooks, most-recently-updated first. This is a Complete Acquisition Feed as defined in OPDS 1.2 §2.5.', '/feeds/opds/all', $webRoot . '/feeds/opds/all.xml', $allEbooks, $opdsRoot, true); $allFeed = new OpdsAcquisitionFeed('All Standard Ebooks', 'All Standard Ebooks, most-recently-updated first. This is a Complete Acquisition Feed as defined in OPDS 1.2 §2.5.', '/feeds/opds/all', $webRoot . '/feeds/opds/all.xml', $allEbooks, $opdsRoot, true);
SaveFeed($allFeed, $force, null, null, $now); SaveFeed($allFeed, $force, null, null, NOW);
// Create the Newest feed. // Create the Newest feed.
$newestFeed = new OpdsAcquisitionFeed('Newest Standard Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/opds/new-releases', $webRoot . '/feeds/opds/new-releases.xml', $newestEbooks, $opdsRoot); $newestFeed = new OpdsAcquisitionFeed('Newest Standard Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/opds/new-releases', $webRoot . '/feeds/opds/new-releases.xml', $newestEbooks, $opdsRoot);
SaveFeed($newestFeed, $force, null, null, $now); SaveFeed($newestFeed, $force, null, null, NOW);
@ -190,11 +188,11 @@ SaveFeed($newestRssFeed, $force, null, null);
// Create the Atom All feed. // Create the Atom All feed.
$allAtomFeed = new AtomFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/feeds/atom/all', $webRoot . '/feeds/atom/all.xml', $allEbooks); $allAtomFeed = new AtomFeed('Standard Ebooks - All Ebooks', 'All Standard Ebooks, most-recently-released first.', '/feeds/atom/all', $webRoot . '/feeds/atom/all.xml', $allEbooks);
SaveFeed($allAtomFeed, $force, null, null, $now); SaveFeed($allAtomFeed, $force, null, null, NOW);
// Create the Atom Newest feed. // Create the Atom Newest feed.
$newestAtomFeed = new AtomFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/atom/new-releases', $webRoot . '/feeds/atom/new-releases.xml', $newestEbooks); $newestAtomFeed = new AtomFeed('Standard Ebooks - Newest Ebooks', 'The ' . number_format($ebooksPerNewestEbooksFeed) . ' latest Standard Ebooks, most-recently-released first.', '/feeds/atom/new-releases', $webRoot . '/feeds/atom/new-releases.xml', $newestEbooks);
SaveFeed($newestAtomFeed, $force, null, null, $now); SaveFeed($newestAtomFeed, $force, null, null, NOW);
// Generate each individual subject feed. // Generate each individual subject feed.
foreach($ebooksBySubject as $subject => $ebooks){ foreach($ebooksBySubject as $subject => $ebooks){
@ -207,7 +205,7 @@ foreach($ebooksBySubject as $subject => $ebooks){
SaveFeed($subjectRssFeed, $force, $subjects[$subject]['name'], $subjects[$subject]['sortedname']); SaveFeed($subjectRssFeed, $force, $subjects[$subject]['name'], $subjects[$subject]['sortedname']);
$subjectAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/subjects/' . Formatter::MakeUrlSafe($subject), $webRoot . '/feeds/atom/subjects/' . Formatter::MakeUrlSafe($subject) . '.xml', $ebooks); $subjectAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/subjects/' . Formatter::MakeUrlSafe($subject), $webRoot . '/feeds/atom/subjects/' . Formatter::MakeUrlSafe($subject) . '.xml', $ebooks);
SaveFeed($subjectAtomFeed, $force, $subjects[$subject]['name'], $subjects[$subject]['sortedname'], $now); SaveFeed($subjectAtomFeed, $force, $subjects[$subject]['name'], $subjects[$subject]['sortedname'], NOW);
} }
// Generate each individual collection feed. // Generate each individual collection feed.
@ -223,7 +221,7 @@ foreach($ebooksByCollection as $collection => $ebooks){
SaveFeed($collectionRssFeed, $force, $collections[$collection]['name'], $collections[$collection]['sortedname']); SaveFeed($collectionRssFeed, $force, $collections[$collection]['name'], $collections[$collection]['sortedname']);
$collectionAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/collections/' . Formatter::MakeUrlSafe($collection), $webRoot . '/feeds/atom/collections/' . Formatter::MakeUrlSafe($collection) . '.xml', $ebooks); $collectionAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/collections/' . Formatter::MakeUrlSafe($collection), $webRoot . '/feeds/atom/collections/' . Formatter::MakeUrlSafe($collection) . '.xml', $ebooks);
SaveFeed($collectionAtomFeed, $force, $collections[$collection]['name'], $collections[$collection]['sortedname'], $now); SaveFeed($collectionAtomFeed, $force, $collections[$collection]['name'], $collections[$collection]['sortedname'], NOW);
} }
// Generate each individual author feed. // Generate each individual author feed.
@ -237,7 +235,7 @@ foreach($ebooksByAuthor as $collection => $ebooks){
SaveFeed($collectionRssFeed, $force, $authors[$collection]['name'], $authors[$collection]['sortedname']); SaveFeed($collectionRssFeed, $force, $authors[$collection]['name'], $authors[$collection]['sortedname']);
$collectionAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/authors/' . $authors[$collection]['id'], $webRoot . '/feeds/atom/authors/' . $authors[$collection]['id'] . '.xml', $ebooks); $collectionAtomFeed = new AtomFeed($title, $subtitle, '/feeds/atom/authors/' . $authors[$collection]['id'], $webRoot . '/feeds/atom/authors/' . $authors[$collection]['id'] . '.xml', $ebooks);
SaveFeed($collectionAtomFeed, $force, $authors[$collection]['name'], $authors[$collection]['sortedname'], $now); SaveFeed($collectionAtomFeed, $force, $authors[$collection]['name'], $authors[$collection]['sortedname'], NOW);
} }
// Set ownership and permissions. // Set ownership and permissions.

View file

@ -46,8 +46,7 @@ $lastSeenTransactionId = null;
$firstTransactionId = null; $firstTransactionId = null;
$transactionFilePath = '/tmp/last-fa-donation'; $transactionFilePath = '/tmp/last-fa-donation';
$transactionIds = []; $transactionIds = [];
$now = new DateTimeImmutable(); $today = NOW->format('n/j/Y');
$today = $now->format('n/j/Y');
$faItemsPerPage = 20; // How many items are on a full page of FA results? $faItemsPerPage = 20; // How many items are on a full page of FA results?
// General plan: Read /tmp/last-fa-donation to see what the last transaction ID was that we processed. // General plan: Read /tmp/last-fa-donation to see what the last transaction ID was that we processed.
@ -94,7 +93,7 @@ try{
} }
if($lastSeenTransactionId === null){ if($lastSeenTransactionId === null){
$log->Write('No last transaction ID, checking everything from ' . $now->format('Y-m-d')); $log->Write('No last transaction ID, checking everything from ' . NOW->format('Y-m-d'));
} }
else{ else{
$log->Write('Checking from last transaction ID ' . $lastSeenTransactionId); $log->Write('Checking from last transaction ID ' . $lastSeenTransactionId);

View file

@ -11,7 +11,6 @@ use function Safe\shell_exec;
// Get a list of payments that are within 1 year / 45 days of today, and deactivate Patrons Circle members who aren't in that list. // Get a list of payments that are within 1 year / 45 days of today, and deactivate Patrons Circle members who aren't in that list.
// We give a 15 day grace period to Patrons Circle members because sometimes FA can be delayed in charging. // We give a 15 day grace period to Patrons Circle members because sometimes FA can be delayed in charging.
$now = new DateTimeImmutable();
$lastYear = new DateTimeImmutable('-1 year'); $lastYear = new DateTimeImmutable('-1 year');
$expiredPatrons = Db::Query(' $expiredPatrons = Db::Query('
@ -29,7 +28,7 @@ $expiredPatrons = Db::Query('
(IsRecurring = false and Amount >= 100 and Created > ? - interval 1 year) (IsRecurring = false and Amount >= 100 and Created > ? - interval 1 year)
) )
) )
', [$now, $now], Patron::class); ', [NOW, NOW], Patron::class);
if(sizeof($expiredPatrons) > 0){ if(sizeof($expiredPatrons) > 0){
$ebooksThisYear = 0; $ebooksThisYear = 0;
@ -54,7 +53,7 @@ if(sizeof($expiredPatrons) > 0){
UPDATE Patrons UPDATE Patrons
set Ended = ? set Ended = ?
where UserId = ? where UserId = ?
', [$now, $patron->UserId]); ', [NOW, $patron->UserId]);
Db::Query(' Db::Query('
UPDATE Benefits UPDATE Benefits

View file

@ -9,8 +9,6 @@ if($artwork === null){
} }
$isEditForm = $isEditForm ?? false; $isEditForm = $isEditForm ?? false;
$now = new DateTimeImmutable('now', new DateTimeZone('America/Juneau')); // Latest continental US time zone
?> ?>
<fieldset> <fieldset>
<legend>Artist details</legend> <legend>Artist details</legend>

View file

@ -1,5 +1,4 @@
<? if($GLOBALS['User'] === null){ <? if($GLOBALS['User'] === null){
// The Kindle browsers renders <aside> as an undismissable popup. Serve a <div> to Kindle instead. See https://github.com/standardebooks/web/issues/204 // The Kindle browsers renders <aside> as an undismissable popup. Serve a <div> to Kindle instead. See https://github.com/standardebooks/web/issues/204
$element = 'aside'; $element = 'aside';
@ -7,10 +6,8 @@
$element = 'div'; $element = 'div';
} }
?> ?>
<<?= $element ?> class="donation"> <<?= $element ?> class="donation">
<p>We rely on your support to help us keep producing beautiful, free, and unrestricted editions of literature for the digital age.</p> <p>We rely on your support to help us keep producing beautiful, free, and unrestricted editions of literature for the digital age.</p>
<p>Will you <a href="/donate">support our efforts with a donation</a>?</p> <p>Will you <a href="/donate">support our efforts with a donation</a>?</p>
</<?= $element ?>> </<?= $element ?>>
<? } ?> <? } ?>

View file

@ -1,12 +1,6 @@
<? <?
use Safe\DateTimeImmutable; // Hide the alert if the user has closed it.
if(!DONATION_DRIVE_COUNTER_ON || ($autoHide ?? $_COOKIE['hide-donation-alert'] ?? false) || NOW > DONATION_DRIVE_COUNTER_END){
$start = new DateTimeImmutable(DONATION_DRIVE_COUNTER_START);
$end = new DateTimeImmutable(DONATION_DRIVE_COUNTER_END);
$now = new DateTimeImmutable();
// Hide the alert if the user has closed it
if(!DONATION_DRIVE_COUNTER_ON || ($autoHide ?? $_COOKIE['hide-donation-alert'] ?? false) || $now > $end){
return; return;
} }
@ -14,12 +8,12 @@ $autoHide = $autoHide ?? true;
$showDonateButton = $showDonateButton ?? true; $showDonateButton = $showDonateButton ?? true;
$current = 0; $current = 0;
if($now < $start || $now > $end){ if(NOW < DONATION_DRIVE_COUNTER_START || NOW > DONATION_DRIVE_COUNTER_END){
return; return;
} }
$deadline = $end->format('F j'); $deadline = DONATION_DRIVE_COUNTER_END->format('F j');
$timeLeft = $now->diff($end); $timeLeft = NOW->diff(DONATION_DRIVE_COUNTER_END);
$timeString = ''; $timeString = '';
if($timeLeft->d < 1 && $timeLeft->h < 20){ if($timeLeft->d < 1 && $timeLeft->h < 20){
$timeString = 'Just hours'; $timeString = 'Just hours';
@ -44,12 +38,11 @@ else{
} }
$digits = str_split(str_pad($current, 3, "0", STR_PAD_LEFT)) $digits = str_split(str_pad($current, 3, "0", STR_PAD_LEFT))
?> ?>
<aside class="donation counter closable"> <aside class="donation counter closable">
<? if($autoHide){ ?> <? if($autoHide){ ?>
<form action="/settings" method="post"> <form action="/settings" method="post">
<input type="hidden" name="hide-donation-alert" value="1" /> <input type="hidden" name="hide-donation-alert" value="true" />
<button class="close" title="Close this box">Close this box</button> <button class="close" title="Close this box">Close this box</button>
</form> </form>
<? } ?> <? } ?>
@ -64,5 +57,9 @@ $digits = str_split(str_pad($current, 3, "0", STR_PAD_LEFT))
<p><strong>Each one-time donation of any amount to Standard Ebooks through <?= $deadline ?> gives us one entry in this $1,000 giveaway.</strong> The more donations we receive through <?= $deadline ?>, the more chances we have to win!</p> <p><strong>Each one-time donation of any amount to Standard Ebooks through <?= $deadline ?> gives us one entry in this $1,000 giveaway.</strong> The more donations we receive through <?= $deadline ?>, the more chances we have to win!</p>
<p><strong>This is a great time to <a href="/donate#patrons-circle">join our Patrons Circle</a> with a one-time donation of $100.</strong> Not only will your donation support us directly, but itll give us one more entry in this big giveaway.</p> <p><strong>This is a great time to <a href="/donate#patrons-circle">join our Patrons Circle</a> with a one-time donation of $100.</strong> Not only will your donation support us directly, but itll give us one more entry in this big giveaway.</p>
<p>Will you show your support for free, beautiful digital literature?</p> <p>Will you show your support for free, beautiful digital literature?</p>
<? if($showDonateButton){ ?><p class="donate-button"><a class="button" href="/donate">Make a one-time donation!</a></p><? } ?> <? if($showDonateButton){ ?>
<p class="donate-button">
<a class="button" href="/donate">Make a one-time donation!</a>
</p>
<? } ?>
</aside> </aside>

View file

@ -1,11 +1,6 @@
<? <?
use Safe\DateTimeImmutable;
$start = new DateTimeImmutable(DONATION_DRIVE_START);
$end = new DateTimeImmutable(DONATION_DRIVE_END);
$now = new DateTimeImmutable();
$totalCurrent = 0; $totalCurrent = 0;
$baseTarget = 25; $baseTarget = 50;
$stretchCurrent = 0; $stretchCurrent = 0;
$stretchTarget = 20; $stretchTarget = 20;
@ -17,9 +12,9 @@ if(
|| ||
$GLOBALS['User'] !== null // If a user is logged in $GLOBALS['User'] !== null // If a user is logged in
|| ||
$start > $now // If the drive hasn't started yet DONATION_DRIVE_START > NOW // If the drive hasn't started yet
|| ||
$now > $end // If the drive has ended NOW > DONATION_DRIVE_END // If the drive has ended
){ ){
return; return;
} }
@ -49,11 +44,11 @@ $totalCurrent = Db::QueryInt('
where Created >= ? where Created >= ?
) )
) x ) x
', [$start, $start, $start]); ', [DONATION_DRIVE_START, DONATION_DRIVE_START, DONATION_DRIVE_START]);
$totalTarget = $baseTarget; $totalTarget = $baseTarget;
$deadline = $end->format('F j'); $deadline = DONATION_DRIVE_END->format('F j');
$timeLeft = $now->diff($end); $timeLeft = NOW->diff(DONATION_DRIVE_END);
$timeString = ''; $timeString = '';
if($timeLeft->days < 1 && $timeLeft->h < 20){ if($timeLeft->days < 1 && $timeLeft->h < 20){
$timeString = 'Just hours'; $timeString = 'Just hours';
@ -83,12 +78,11 @@ if($stretchTarget > 0 && $totalCurrent >= $baseTarget){
$stretchCurrent = $totalCurrent - $baseTarget; $stretchCurrent = $totalCurrent - $baseTarget;
$totalTarget = $baseTarget + $stretchTarget; $totalTarget = $baseTarget + $stretchTarget;
} }
?> ?>
<aside class="donation closable"> <aside class="donation closable">
<? if($autoHide){ ?> <? if($autoHide){ ?>
<form action="/settings" method="post"> <form action="/settings" method="post">
<input type="hidden" name="hide-donation-alert" value="1" /> <input type="hidden" name="hide-donation-alert" value="true" />
<button class="close" title="Close this box">Close this box</button> <button class="close" title="Close this box">Close this box</button>
</form> </form>
<? } ?> <? } ?>
@ -115,7 +109,9 @@ if($stretchTarget > 0 && $totalCurrent >= $baseTarget){
<p class="target"><?= number_format($totalTarget) ?></p> <p class="target"><?= number_format($totalTarget) ?></p>
</div> </div>
<progress max="<?= $baseTarget ?>" value="<?= $totalCurrent - $stretchCurrent ?>"></progress> <progress max="<?= $baseTarget ?>" value="<?= $totalCurrent - $stretchCurrent ?>"></progress>
<? if($stretchOn){ ?><progress class="stretch" max="<?= $stretchTarget ?>" value="<?= $stretchCurrent ?>"></progress><? } ?> <? if($stretchOn){ ?>
<progress class="stretch" max="<?= $stretchTarget ?>" value="<?= $stretchCurrent ?>"></progress>
<? } ?>
</div> </div>
<? if($stretchOn){ ?> <? if($stretchOn){ ?>
<p>When we started this drive, we set a goal of <?= number_format($baseTarget) ?> Patrons Circle members by <?= $deadline ?>. Thanks to the incredible generosity of literature lovers like you, we hit that goal!</p> <p>When we started this drive, we set a goal of <?= number_format($baseTarget) ?> Patrons Circle members by <?= $deadline ?>. Thanks to the incredible generosity of literature lovers like you, we hit that goal!</p>
@ -124,5 +120,9 @@ if($stretchTarget > 0 && $totalCurrent >= $baseTarget){
<p>It takes a huge amount of resources and highly-skilled work to create and distribute each of our free ebooks, and we need your support to keep it up. Thats why we want to welcome <?= number_format($baseTarget) ?> new patrons by <?= $deadline ?>. Its our patrons who keep us on the stable financial footing we need to continue producing and giving away beautiful ebooks.</p> <p>It takes a huge amount of resources and highly-skilled work to create and distribute each of our free ebooks, and we need your support to keep it up. Thats why we want to welcome <?= number_format($baseTarget) ?> new patrons by <?= $deadline ?>. Its our patrons who keep us on the stable financial footing we need to continue producing and giving away beautiful ebooks.</p>
<p>Will you become a patron, and support free and unrestricted digital literature?</p> <p>Will you become a patron, and support free and unrestricted digital literature?</p>
<? } ?> <? } ?>
<? if($showDonateButton){ ?><p class="donate-button"><a class="button" href="/donate#patrons-circle">Join the patrons circle</a></p><? } ?> <? if($showDonateButton){ ?>
<p class="donate-button">
<a class="button" href="/donate#patrons-circle">Join the patrons circle</a>
</p>
<? } ?>
</aside> </aside>

View file

@ -25,7 +25,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"" . S
<title>Search Results</title> <title>Search Results</title>
<subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle> <subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle>
<icon><?= SITE_URL ?>/images/logo.png</icon> <icon><?= SITE_URL ?>/images/logo.png</icon>
<updated><?= (new DateTimeImmutable())->Format('Y-m-d\TH:i:s\Z') ?></updated> <updated><?= NOW->format('Y-m-d\TH:i:s\Z') ?></updated>
<author> <author>
<name>Standard Ebooks</name> <name>Standard Ebooks</name>
<uri><?= SITE_URL ?></uri> <uri><?= SITE_URL ?></uri>

View file

@ -26,7 +26,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"". SI
<title>Search Results</title> <title>Search Results</title>
<subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle> <subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle>
<icon><?= SITE_URL ?>/images/logo.png</icon> <icon><?= SITE_URL ?>/images/logo.png</icon>
<updated><?= (new DateTimeImmutable())->Format('Y-m-d\TH:i:s\Z') ?></updated> <updated><?= NOW->format('Y-m-d\TH:i:s\Z') ?></updated>
<author> <author>
<name>Standard Ebooks</name> <name>Standard Ebooks</name>
<uri><?= SITE_URL ?></uri> <uri><?= SITE_URL ?></uri>

View file

@ -24,7 +24,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"" . S
<description>Results for <?= Formatter::EscapeXml($query) ?>”.</description> <description>Results for <?= Formatter::EscapeXml($query) ?>”.</description>
<language>en-US</language> <language>en-US</language>
<copyright>https://creativecommons.org/publicdomain/zero/1.0/</copyright> <copyright>https://creativecommons.org/publicdomain/zero/1.0/</copyright>
<lastBuildDate><?= (new DateTimeImmutable())->format('r') ?></lastBuildDate> <lastBuildDate><?= NOW->format('r') ?></lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs> <docs>http://blogs.law.harvard.edu/tech/rss</docs>
<atom:link href="<?= SITE_URL ?>/feeds/rss/all?query=<?= urlencode($query) ?>" rel="self" type="application/rss+xml"/> <atom:link href="<?= SITE_URL ?>/feeds/rss/all?query=<?= urlencode($query) ?>" rel="self" type="application/rss+xml"/>
<atom:link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" /> <atom:link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" />

View file

@ -7,7 +7,7 @@ $canVote = true; // Allow non-logged-in users to see the 'vote' button
try{ try{
$poll = Poll::GetByUrlName(HttpInput::Str(GET, 'pollurlname')); $poll = Poll::GetByUrlName(HttpInput::Str(GET, 'pollurlname'));
if(!$poll->IsActive() && $poll->End !== null && $poll->End < new DateTimeImmutable()){ if(!$poll->IsActive() && $poll->End !== null && $poll->End < NOW){
// If the poll ended, redirect to the results // If the poll ended, redirect to the results
header('Location: ' . $poll->Url . '/votes'); header('Location: ' . $poll->Url . '/votes');
exit(); exit();
@ -47,7 +47,7 @@ catch(Exceptions\AppException){
<a href="<?= $poll->Url ?>/votes" class="button">View results</a> <a href="<?= $poll->Url ?>/votes" class="button">View results</a>
</p> </p>
<? }else{ ?> <? }else{ ?>
<? if($poll->Start !== null && $poll->Start > new DateTimeImmutable()){ ?> <? if($poll->Start !== null && $poll->Start > NOW){ ?>
<p class="center-notice">This poll opens on <?= $poll->Start->format('F j, Y g:i a') ?>.</p> <p class="center-notice">This poll opens on <?= $poll->Start->format('F j, Y g:i a') ?>.</p>
<? }else{ ?> <? }else{ ?>
<p class="center-notice">This poll closed on <?= $poll->End->format('F j, Y g:i a') ?>.</p> <p class="center-notice">This poll closed on <?= $poll->End->format('F j, Y g:i a') ?>.</p>