diff --git a/lib/Enums/ExceptionMessageType.php b/lib/Enums/ExceptionMessageType.php new file mode 100644 index 00000000..2ceed418 --- /dev/null +++ b/lib/Enums/ExceptionMessageType.php @@ -0,0 +1,7 @@ + +namespace Enums; + +enum ExceptionMessageType{ + case Html; + case Text; +} diff --git a/lib/Exceptions/AppException.php b/lib/Exceptions/AppException.php index 3b0219db..9c2bb0d2 100644 --- a/lib/Exceptions/AppException.php +++ b/lib/Exceptions/AppException.php @@ -2,4 +2,5 @@ namespace Exceptions; class AppException extends \Exception{ + public \Enums\ExceptionMessageType $MessageType = \Enums\ExceptionMessageType::Text; } diff --git a/lib/Formatter.php b/lib/Formatter.php index c8456c12..ac45ee27 100644 --- a/lib/Formatter.php +++ b/lib/Formatter.php @@ -4,6 +4,7 @@ use function Safe\preg_replace; class Formatter{ private static Transliterator $_Transliterator; private static Parsedown $_MarkdownParser; + private static NumberFormatter $_NumberFormatter; /** * Remove diacritics from a string, leaving the now-unaccented characters in place. @@ -122,4 +123,32 @@ class Formatter{ return $output; } + + /** + * Format a float into a USD currency string. The result is prepended with `$`. + * + * @param ?float $amount The amount to format. + * @param bool $trimZeroCents If `$amount` has zero cents, don't include the cents value. + */ + public static function FormatCurrency(?float $amount, bool $trimZeroCents = false): string{ + if($amount === null){ + $amount = 0; + } + + if(!isset(Formatter::$_NumberFormatter)){ + Formatter::$_NumberFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY); + } + + $output = Formatter::$_NumberFormatter->formatCurrency($amount, 'USD'); + + if($output === false){ + $output = '$0.00'; + } + + if($trimZeroCents){ + $output = preg_replace('/\.00$/u', '', $output); + } + + return $output; + } } diff --git a/lib/Session.php b/lib/Session.php index 3c017e00..320be09c 100644 --- a/lib/Session.php +++ b/lib/Session.php @@ -1,4 +1,6 @@ + +use Exceptions\InvalidLoginException; use Ramsey\Uuid\Uuid; use Safe\DateTimeImmutable; @@ -72,7 +74,21 @@ class Session{ self::SetSessionCookie($this->SessionId); } catch(Exceptions\UserNotFoundException){ - throw new Exceptions\InvalidLoginException(); + // We couldn't find a *registered * `User`. But, often people make a small donation assuming it automatically adds them to the Patrons Circle. So, check if they made a donation less than 7 days ago, and if so, notify them about the requirements to join the Patrons Circle. + $ex = new Exceptions\InvalidLoginException(); + try{ + $user = User::GetByIdentifier($identifier); + /** @throws void */ + if($user->LastPayment !== null && $user->LastPayment->Created > new DateTimeImmutable('7 days ago')){ + $ex = new InvalidLoginException('
We couldn’t find you in the Patrons Circle, but you recently ' . ($user->LastPayment->IsRecurring ? 'started a recurring' : 'made a one-time') . ' donation of ' . Formatter::FormatCurrency($user->LastPayment->Amount) . '.
To join the Patrons Circle, supporters must start a recurring donation of ' . Formatter::FormatCurrency(PATRONS_CIRCLE_MONTHLY_COST, true) . '/month or more, or make a one-time donation of ' . Formatter::FormatCurrency(PATRONS_CIRCLE_YEARLY_COST, true) . ' or more to join for one year.
Once you join the Patrons Circle, you’ll be able to log in and access member benefits.
'); + $ex->MessageType = Enums\ExceptionMessageType::Html; + } + } + catch(Exceptions\UserNotFoundException){ + // Pass. + } + + throw $ex; } } diff --git a/lib/User.php b/lib/User.php index 6edf2447..02fda675 100644 --- a/lib/User.php +++ b/lib/User.php @@ -11,6 +11,7 @@ use function Safe\preg_match; * @property string $Url * @property ?Patron $Patron * @property ?NewsletterSubscription $NewsletterSubscription + * @property ?Payment $LastPayment */ class User{ use Traits\Accessor; @@ -27,6 +28,7 @@ class User{ protected bool $_IsRegistered; /** @var arrayOur fiscal sponsor, Fractured Atlas, is celebrating the twenty-year anniversary of their fiscal sponsorship program by distributing $1,000 to twenty different projects.
Each one-time donation of any amount to Standard Ebooks through = $deadline ?> gives us one entry in this $1,000 giveaway. The more donations we receive through = $deadline ?>, the more chances we have to win!
-This is a great time to join our Patrons Circle with a donation of $= number_format(PATRONS_CIRCLE_YEARLY_COST) ?>. Not only will your donation support us directly, but it’ll give us one more entry in this big giveaway.
+This is a great time to join our Patrons Circle with a donation of = Formatter::FormatCurrency(PATRONS_CIRCLE_YEARLY_COST, true) ?>. Not only will your donation support us directly, but it’ll give us one more entry in this big giveaway.
Will you show your support for free, beautiful digital literature?
if($showDonateButton){ ?> diff --git a/www/donate/index.php b/www/donate/index.php index 2541bcec..d7d8441b 100644 --- a/www/donate/index.php +++ b/www/donate/index.php @@ -34,10 +34,10 @@ $newsletterSubscriberCount = floor(Db::QueryInt('Membership in the Patrons Circle is limited to individuals only. Organizations, please see corporate sponsorship instead.
Join the Patrons Circle by starting a recurring donation of $= number_format(PATRONS_CIRCLE_MONTHLY_COST) ?>/month or more, or join for one year with a one-time donation of $= number_format(PATRONS_CIRCLE_YEARLY_COST) ?> or more.
+Join the Patrons Circle by starting a recurring donation of = Formatter::FormatCurrency(PATRONS_CIRCLE_MONTHLY_COST, true) ?>/month or more, or join for one year with a one-time donation of = Formatter::FormatCurrency(PATRONS_CIRCLE_YEARLY_COST, true) ?> or more.
Important: We need to know your email address to be able to log you in to the Patrons Circle. Make sure to select either “List my name publicly” or “Don’t list publicly, but reveal to project” during checkout to be able to log in to the Patrons Circle.