From 32206f3cd7131a1149b8491398dadc9ee68bed91 Mon Sep 17 00:00:00 2001 From: Alex Cabal Date: Wed, 29 Jun 2022 18:05:49 -0500 Subject: [PATCH] Improve handling of returning patrons --- lib/Db.php | 20 +++++++++++++ lib/Patron.php | 29 +++++++------------ lib/Poll.php | 2 +- lib/PollItem.php | 2 +- lib/Vote.php | 6 ++-- scripts/process-pending-payments | 32 ++++++++------------- templates/DonationProgress.php | 2 +- templates/EmailPatronsCircleWelcome.php | 8 +++--- templates/EmailPatronsCircleWelcomeText.php | 11 ++++--- www/about/index.php | 4 +-- 10 files changed, 61 insertions(+), 55 deletions(-) diff --git a/lib/Db.php b/lib/Db.php index bc65593c..6d803dd3 100644 --- a/lib/Db.php +++ b/lib/Db.php @@ -19,4 +19,24 @@ class Db{ return $GLOBALS['DbConnection']->Query($query, $args, $class); } + + public static function QueryInt(string $query, array $args = []): int{ + // Useful for queries that return a single integer as a result, like count(*) or sum(*). + + if(!isset($GLOBALS['DbConnection'])){ + $GLOBALS['DbConnection'] = new DbConnection(DATABASE_DEFAULT_DATABASE, DATABASE_DEFAULT_HOST); + } + + if(!is_array($args)){ + $args = [$args]; + } + + $result = $GLOBALS['DbConnection']->Query($query, $args); + + if(sizeof($result) > 0){ + return current((Array)$result[0]); + } + + return 0; + } } diff --git a/lib/Patron.php b/lib/Patron.php index a7f96142..6519f6d8 100644 --- a/lib/Patron.php +++ b/lib/Patron.php @@ -6,7 +6,7 @@ class Patron extends PropertiesBase{ public $UserId = null; public $IsAnonymous; public $AlternateName; - public $IsSubscribedToEmail; + public $IsSubscribedToEmails; public $Created = null; public $Ended = null; @@ -30,35 +30,26 @@ class Patron extends PropertiesBase{ return $result[0]; } - public function Create(bool $sendEmail = true): void{ + public function Create(): void{ $this->Created = new DateTime(); + Db::Query('INSERT into Patrons (Created, UserId, IsAnonymous, AlternateName, IsSubscribedToEmails) values(?, ?, ?, ?, ?);', [$this->Created, $this->UserId, $this->IsAnonymous, $this->AlternateName, $this->IsSubscribedToEmails]); - Db::Query('INSERT into Patrons (Created, UserId, IsAnonymous, AlternateName, IsSubscribedToEmail) values(?, ?, ?, ?, ?);', [$this->Created, $this->UserId, $this->IsAnonymous, $this->AlternateName, $this->IsSubscribedToEmail]); + // If this is a patron for the first time, send the first-time patron email. + // Otherwise, send the returning patron email. + $isReturning = Db::QueryInt('SELECT count(*) from Patrons where UserId = ?', [$this->UserId]) > 1; - if($sendEmail){ - $this->SendWelcomeEmail(); - } + $this->SendWelcomeEmail($isReturning); } - public function Reactivate(bool $sendEmail = true): void{ - Db::Query('UPDATE Patrons set Created = utc_timestamp(), Ended = null, IsAnonymous = ?, IsSubscribedToEmail = ?, AlternateName = ? where UserId = ?;', [$this->IsAnonymous, $this->IsSubscribedToEmail, $this->AlternateName, $this->UserId]); - $this->Created = new DateTime(); - $this->Ended = null; - - if($sendEmail){ - $this->SendWelcomeEmail(); - } - } - - private function SendWelcomeEmail(): void{ + private function SendWelcomeEmail(bool $isReturning): void{ $this->__get('User'); if($this->User !== null){ $em = new Email(); $em->To = $this->User->Email; $em->From = EDITOR_IN_CHIEF_EMAIL_ADDRESS; $em->Subject = 'Thank you for supporting Standard Ebooks!'; - $em->Body = Template::EmailPatronsCircleWelcome(['isAnonymous' => $this->IsAnonymous]); - $em->TextBody = Template::EmailPatronsCircleWelcomeText(['isAnonymous' => $this->IsAnonymous]); + $em->Body = Template::EmailPatronsCircleWelcome(['isAnonymous' => $this->IsAnonymous, 'isReturning' => $isReturning]); + $em->TextBody = Template::EmailPatronsCircleWelcomeText(['isAnonymous' => $this->IsAnonymous, 'isReturning' => $isReturning]); $em->Send(); } } diff --git a/lib/Poll.php b/lib/Poll.php index a27e540d..0009e0ea 100644 --- a/lib/Poll.php +++ b/lib/Poll.php @@ -25,7 +25,7 @@ class Poll extends PropertiesBase{ protected function GetVoteCount(): int{ if($this->VoteCount === null){ - $this->VoteCount = (Db::Query('select count(*) as VoteCount from Votes v inner join PollItems pi on v.PollItemId = pi.PollItemId where pi.PollId = ?', [$this->PollId]))[0]->VoteCount; + $this->VoteCount = Db::QueryInt('select count(*) from Votes v inner join PollItems pi on v.PollItemId = pi.PollItemId where pi.PollId = ?', [$this->PollId]); } return $this->VoteCount; diff --git a/lib/PollItem.php b/lib/PollItem.php index d22878ac..688983a6 100644 --- a/lib/PollItem.php +++ b/lib/PollItem.php @@ -9,7 +9,7 @@ class PollItem extends PropertiesBase{ protected function GetVoteCount(): int{ if($this->VoteCount === null){ - $this->VoteCount = (Db::Query('select count(*) as VoteCount from Votes v inner join PollItems pi on v.PollItemId = pi.PollItemId where pi.PollItemId = ?', [$this->PollItemId]))[0]->VoteCount; + $this->VoteCount = Db::QueryInt('select count(*) from Votes v inner join PollItems pi on v.PollItemId = pi.PollItemId where pi.PollItemId = ?', [$this->PollItemId]); } return $this->VoteCount; diff --git a/lib/Vote.php b/lib/Vote.php index 9c243294..fea7507c 100644 --- a/lib/Vote.php +++ b/lib/Vote.php @@ -49,10 +49,10 @@ class Vote extends PropertiesBase{ } else{ // Do we already have a vote for this poll, from this user? - if( (Db::Query(' - SELECT count(*) as VoteCount from Votes v inner join + if(Db::QueryInt(' + SELECT count(*) from Votes v inner join (select PollItemId from PollItems pi inner join Polls p on pi.PollId = p.PollId) x - on v.PollItemId = x.PollItemId where v.UserId = ?', [$this->UserId]))[0]->VoteCount > 0){ + on v.PollItemId = x.PollItemId where v.UserId = ?', [$this->UserId]) > 0){ $error->Add(new Exceptions\VoteExistsException()); } } diff --git a/scripts/process-pending-payments b/scripts/process-pending-payments index ed1bdb84..a9963e17 100755 --- a/scripts/process-pending-payments +++ b/scripts/process-pending-payments @@ -68,6 +68,11 @@ try{ foreach($pendingPayments as $pendingPayment){ if($pendingPayment->ChannelId == PAYMENT_CHANNEL_FA){ + if(Db::QueryInt('SELECT count(*) from Payments where TransactionId = ? limit 1', [$pendingPayment->TransactionId]) > 0){ + $log->Write('Donation already exists in database.'); + continue; + } + $log->Write('Processing donation ' . $pendingPayment->TransactionId . ' ...'); $driver->get('https://fundraising.fracturedatlas.org/admin/donations?query=' . $pendingPayment->TransactionId); @@ -160,21 +165,14 @@ try{ if(($payment->IsRecurring && $payment->Amount >= 10 && $payment->Created >= $lastMonth) || ($payment->Amount >= 100 && $payment->Created >= $lastYear)){ // This payment is eligible for the Patrons Circle. // Are we already a patron? - try{ - $patron = Patron::Get($payment->UserId); - } - catch(Exceptions\InvalidPatronException $ex){ + if(!Db::QueryInt('SELECT count(*) from Patrons where UserId = ? and Ended is not null', [$payment->UserId])){ // Not a patron yet, add them to the Patrons Circle + $patron = new Patron(); $patron->UserId = $payment->UserId; $patron->User = $payment->User; - } - - if($patron->Created === null || $patron->Ended !== null){ - // If we're a new patron, or an old patron that was deactivated, - // re-enable them as a patron in the system $patron->IsAnonymous = (trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::td[normalize-space(.) = "Attribution"]]'))->getText()) == 'Private'); - $patron->IsSubscribedToEmail = $patron->User !== null && $patron->User->Email !== null; + $patron->IsSubscribedToEmails = $patron->User !== null && $patron->User->Email !== null; try{ $patron->AlternateName = trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::td[normalize-space(.) = "Attribution Text"]]'))->getText()); @@ -182,20 +180,14 @@ try{ catch(Exception $ex){ } - if($patron->Created === null){ - $log->Write('Adding donor as patron ...'); - $patron->Create(); - } - elseif($patron->Ended !== null){ - $log->Write('Reactivating donor as patron ...'); - $patron->Reactivate(); - } + $log->Write('Adding donor as patron ...'); + $patron->Create(); } } else{ - // Not a patron; send a thank you email anyway, but only if this is a non-recurring donation, + // Not eligible to be a patron; send a thank you email anyway, but only if this is a non-recurring donation, // or if it's their very first recurring donation - $previousPaymentCount = (Db::Query('SELECT count(*) as PreviousPaymentCount from Payments where UserId = ? and IsRecurring = true', [$payment->UserId]))[0]->PreviousPaymentCount; + $previousPaymentCount = Db::QueryInt('SELECT count(*) from Payments where UserId = ? and IsRecurring = true', [$payment->UserId]); // We just added a payment to the system, so if this is their very first recurring payment, we expect the count to be exactly 1 if(!$payment->IsRecurring || $previousPaymentCount == 1){ diff --git a/templates/DonationProgress.php b/templates/DonationProgress.php index 58d7ee45..61c977c7 100644 --- a/templates/DonationProgress.php +++ b/templates/DonationProgress.php @@ -9,7 +9,7 @@ $startDate = new DateTime('2022-07-01'); $endDate = new DateTime('2022-07-31'); $autoHide = $autoHide ?? true; $showDonateButton = $showDonateButton ?? true; -$current = (Db::Query('SELECT count(*) as PatronCount from Patrons where Created >= ?', [$startDate]))[0]->PatronCount; +$current = Db::QueryInt('SELECT count(*) from Patrons where Created >= ?', [$startDate]); $target = 70; $stretchCurrent = 0; $stretchTarget = 20; diff --git a/templates/EmailPatronsCircleWelcome.php b/templates/EmailPatronsCircleWelcome.php index 86cb73c9..e159faf3 100644 --- a/templates/EmailPatronsCircleWelcome.php +++ b/templates/EmailPatronsCircleWelcome.php @@ -7,13 +7,13 @@

Hello,

I wanted to thank you personally for your recent donation to Standard Ebooks. Your donation will go towards continuing our mission of producing and distributing high-quality ebooks that are free of cost and free of copyright restrictions. Donations like yours help ensure that the world's literature is available in beautiful editions made for the digital age.

-

I'm pleased to be able to include you in our Patrons Circle. Since you indicated you want your donation to remain anonymous, I haven't listed your name on our masthead. If you do prefer to have your name listed, just let me know.

+

I'm pleased to be able to welcome you back toinclude you in our Patrons Circle. Since you indicated you want your donation to remain anonymous, I haven't listed your name on our masthead. If you do prefer to have your name listed, just let me know.

-

I'm pleased to be able to include you in our Patrons Circle, with your name listed on our masthead for the duration of your donation. If you'd like to use a different name than the one you entered on our donation form, just let me know.

+

I'm pleased to be able to welcome you back toinclude you in our Patrons Circle, with your name listed on our masthead for the duration of your donation. If you'd like to use a different name than the one you entered on our donation form, just let me know.

As a Patron, once per quarter you may suggest a book for inclusion in our Wanted Ebooks list. Before submitting a suggestion, please review our collections policy; then you can contact me directly at with your selection.

-

If I may ask, how did you hear about Standard Ebooks? Having an idea of where our readers and supporters find out about us is extremely helpful.

-

Please don't hesitate to contact me if you have questions or suggestions. Thanks again for your donation, and for supporting the literate arts!

+

If I may ask, how did you hear about Standard Ebooks? Having an idea of where our readers and supporters find out about us is extremely helpful.

+

As always, pleasePlease don't hesitate to contact me if you have questions or suggestions. Thanks again for your donation, and for supporting the literate arts!