mirror of
https://github.com/standardebooks/web.git
synced 2025-07-12 09:32:24 -04:00
Improve handling of returning patrons
This commit is contained in:
parent
dbefba6b94
commit
32206f3cd7
10 changed files with 61 additions and 55 deletions
20
lib/Db.php
20
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
<p>Hello,</p>
|
||||
<p>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.</p>
|
||||
<? if($isAnonymous){ ?>
|
||||
<p>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.</p>
|
||||
<p>I'm pleased to be able to <? if($isReturning){ ?>welcome you back to<? }else{ ?>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.</p>
|
||||
<? }else{ ?>
|
||||
<p>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.</p>
|
||||
<p>I'm pleased to be able to <? if($isReturning){ ?>welcome you back to<? }else{ ?>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.</p>
|
||||
<? } ?>
|
||||
<p>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 <a href="https://standardebooks.org/contribute/collections-policy">collections policy</a>; then you can contact me directly at <a href="mailto:<?= EDITOR_IN_CHIEF_EMAIL_ADDRESS ?>"><?= EDITOR_IN_CHIEF_EMAIL_ADDRESS ?></a> with your selection.</p>
|
||||
<p>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.</p>
|
||||
<p>Please don't hesitate to contact me if you have questions or suggestions. Thanks again for your donation, and for supporting the literate arts!</p>
|
||||
<? if(!$isReturning){ ?><p>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.</p><? } ?>
|
||||
<p><? if($isReturning){ ?>As always, please<? }else{ ?>Please<? } ?> don't hesitate to contact me if you have questions or suggestions. Thanks again for your donation, and for supporting the literate arts!</p>
|
||||
<footer style="margin-top: 2em;">
|
||||
<p>Alex Cabal</p>
|
||||
<p>S.E. Editor-in-Chief</p>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
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.
|
||||
|
||||
<? if($isAnonymous){ ?>
|
||||
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 <? if($isReturning){ ?>welcome you back to<? }else{ ?>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.
|
||||
<? }else{ ?>
|
||||
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 <? if($isReturning){ ?>welcome you back to<? }else{ ?>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.
|
||||
<? } ?>
|
||||
|
||||
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, at <https://standardebooks.org/contribute/collections-policy>; then you can contact me directly at <?= EDITOR_IN_CHIEF_EMAIL_ADDRESS ?> with your selection.
|
||||
<? if(!$isReturning){ ?>
|
||||
|
||||
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.
|
||||
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($isReturning){ ?>As always, please<? }else{ ?>Please<? } ?> don't hesitate to contact me if you have questions or suggestions. Thanks again for your donation, and for supporting the literate arts!
|
||||
|
||||
|
||||
Alex Cabal
|
||||
|
|
|
@ -16,7 +16,7 @@ $patronsCircle = Db::Query('SELECT if(p.AlternateName is not null, p.AlternateNa
|
|||
order by regexp_substr(SortedName, "[\\\p{Lu}][\\\p{L}\-]+$") asc;
|
||||
');
|
||||
|
||||
$anonymousPatronCount = Db::Query('SELECT sum(cnt) as AnonymousPatronCount
|
||||
$anonymousPatronCount = Db::QueryInt('SELECT sum(cnt)
|
||||
from
|
||||
(
|
||||
(
|
||||
|
@ -39,7 +39,7 @@ $anonymousPatronCount = Db::Query('SELECT sum(cnt) as AnonymousPatronCount
|
|||
Ended is null
|
||||
)
|
||||
) x
|
||||
')[0]->AnonymousPatronCount;
|
||||
');
|
||||
|
||||
?><?= Template::Header(['title' => 'About Standard Ebooks', 'highlight' => 'about', 'description' => 'Standard Ebooks is a volunteer-driven effort to produce a collection of high quality, carefully formatted, accessible, open source, and free public domain ebooks that meet or exceed the quality of commercially produced ebooks. The text and cover art in our ebooks is already believed to be in the public domain, and Standard Ebook dedicates its own work to the public domain, thus releasing the entirety of each ebook file into the public domain.']) ?>
|
||||
<main>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue