diff --git a/src/app/EventLog.php b/src/app/EventLog.php index 04f43908..2c695653 100644 --- a/src/app/EventLog.php +++ b/src/app/EventLog.php @@ -1,131 +1,134 @@ The attributes that are mass assignable */ protected $fillable = [ 'comment', // extra event info (json) 'data', 'type', // user, domain, etc. 'object_id', 'object_type', // actor, if any 'user_email', ]; /** @var array Casts properties as type */ protected $casts = [ 'created_at' => 'datetime:Y-m-d H:i:s', 'data' => 'array', 'type' => 'integer', ]; /** @var array The attributes that can be not set */ protected $nullable = ['comment', 'data', 'user_email']; /** @var string Database table name */ protected $table = 'eventlog'; /** @var bool Indicates if the model should be timestamped. */ public $timestamps = false; /** * Create an eventlog object for a specified object. * * @param object $object Object (User, Domain, etc.) * @param int $type Event type (use one of EventLog::TYPE_* consts) * @param ?string $comment Event description * @param ?array $data Extra information * * @return EventLog */ public static function createFor($object, int $type, string $comment = null, array $data = null): EventLog { $event = self::create([ 'object_id' => $object->id, 'object_type' => get_class($object), 'type' => $type, 'comment' => $comment, 'data' => $data, ]); return $event; } /** * Principally an object such as Domain, User, Group. * Note that it may be trashed (soft-deleted). * * @return mixed */ public function object() { return $this->morphTo()->withTrashed(); // @phpstan-ignore-line } /** * Get an event type name. * * @return ?string Event type name */ public function eventName(): ?string { switch ($this->type) { case self::TYPE_SUSPENDED: return \trans('app.event-suspended'); case self::TYPE_UNSUSPENDED: return \trans('app.event-unsuspended'); case self::TYPE_COMMENT: return \trans('app.event-comment'); + case self::TYPE_MAILSENT: + return \trans('app.event-mailsent'); default: return null; } } /** * Event type mutator * * @throws \Exception */ public function setTypeAttribute($type) { if (!is_numeric($type)) { throw new \Exception("Expecting an event type to be numeric"); } $type = (int) $type; if ($type < 0 || $type > 255) { throw new \Exception("Expecting an event type between 0 and 255"); } $this->attributes['type'] = $type; } } diff --git a/src/app/Mail/DegradedAccountReminder.php b/src/app/Mail/DegradedAccountReminder.php index 2f791783..ddbbb8cd 100644 --- a/src/app/Mail/DegradedAccountReminder.php +++ b/src/app/Mail/DegradedAccountReminder.php @@ -1,82 +1,73 @@ wallet = $wallet; $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $subject = \trans('mail.degradedaccountreminder-subject', ['site' => $appName]); $this->view('emails.html.degraded_account_reminder') ->text('emails.plain.degraded_account_reminder') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, 'username' => $this->user->name(true), 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id), 'dashboardUrl' => Utils::serviceUrl('/dashboard', $this->user->tenant_id), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $wallet = new Wallet(); $user = new User(); $mail = new self($wallet, $user); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/Helper.php b/src/app/Mail/Helper.php index bb7c8905..66ccc1a0 100644 --- a/src/app/Mail/Helper.php +++ b/src/app/Mail/Helper.php @@ -1,134 +1,131 @@ build(); // @phpstan-ignore-line $mailer = \Illuminate\Container\Container::getInstance()->make('mailer'); return $mailer->render(['text' => $mail->textView], $mail->buildViewData()); - } elseif ($type != 'html') { + } + + if ($type != 'html') { throw new \Exception("Unsupported output format"); } // HTML output return $mail->build()->render(); // @phpstan-ignore-line } /** * Sends an email * * @param Mailable $mail Email content generator * @param int|null $tenantId Tenant identifier * @param array $params Email parameters: to, cc * * @throws \Exception */ public static function sendMail(Mailable $mail, $tenantId = null, array $params = []): void { - $class = explode("\\", get_class($mail)); - $class = end($class); - - $getRecipients = function () use ($params) { - $recipients = []; - - // For now we do not support addresses + names, only addresses - foreach (['to', 'cc'] as $idx) { - if (!empty($params[$idx])) { - if (is_array($params[$idx])) { - $recipients = array_merge($recipients, $params[$idx]); - } else { - $recipients[] = $params[$idx]; - } + $class = class_basename(get_class($mail)); + $recipients = []; + + // For now we do not support addresses + names, only addresses + foreach (['to', 'cc'] as $idx) { + if (!empty($params[$idx])) { + if (is_array($params[$idx])) { + $recipients = array_merge($recipients, $params[$idx]); + } else { + $recipients[] = $params[$idx]; } } - - return implode(', ', $recipients); - }; + } try { if (!empty($params['to'])) { $mail->to($params['to']); } if (!empty($params['cc'])) { $mail->cc($params['cc']); } $fromAddress = Tenant::getConfig($tenantId, 'mail.from.address'); $fromName = Tenant::getConfig($tenantId, 'mail.from.name'); $replytoAddress = Tenant::getConfig($tenantId, 'mail.reply_to.address'); $replytoName = Tenant::getConfig($tenantId, 'mail.reply_to.name'); if ($fromAddress) { $mail->from($fromAddress, $fromName); } if ($replytoAddress) { $mail->replyTo($replytoAddress, $replytoName); } Mail::send($mail); - $msg = sprintf("[%s] Sent mail to %s%s", $class, $getRecipients(), $params['add'] ?? ''); - - \Log::info($msg); + if ($user = $mail->getUser()) { + $comment = "[{$class}] " . $mail->getSubject(); + EventLog::createFor($user, EventLog::TYPE_MAILSENT, $comment, ['recipients' => $recipients]); + } } catch (\Exception $e) { $format = "[%s] Failed to send mail to %s%s: %s"; - $msg = sprintf($format, $class, $getRecipients(), $params['add'] ?? '', $e->getMessage()); + $msg = sprintf($format, $class, implode(', ', $recipients), $params['add'] ?? '', $e->getMessage()); \Log::error($msg); throw $e; } } /** * Return user's email addresses, separately for use in To and Cc. * * @param \App\User $user The user * @param bool $external Include users's external email * * @return array To address as the first element, Cc address(es) as the second. */ public static function userEmails(\App\User $user, bool $external = false): array { $active = $user->isLdapReady() && $user->isImapReady(); // Sending an email to non-(ldap|imap)-ready user will fail, skip it // (or send to the external email only, when appropriate) $to = $active ? $user->email : null; $cc = []; // If user has no mailbox entitlement we should not send // the email to his main address, but use external address, if defined if ($active && !$user->hasSku('mailbox')) { $to = $user->getSetting('external_email'); } elseif ($external) { $ext_email = $user->getSetting('external_email'); if ($ext_email && $ext_email != $to) { $cc[] = $ext_email; } } return [$to, $cc]; } } diff --git a/src/app/Mail/Mailable.php b/src/app/Mail/Mailable.php new file mode 100644 index 00000000..16b7c8fc --- /dev/null +++ b/src/app/Mail/Mailable.php @@ -0,0 +1,55 @@ +user; + } + + /** + * Returns the mail subject. + * + * @return string Mail subject + */ + public function getSubject(): string + { + if ($this->subject) { + return $this->subject; + } + + // Subject property is not available before build() method was called + // i.e. before Mail::send(). + // It's also not available when using Mail::fake(). + // This is essentially why we have getSubject() method. + + $class = class_basename(static::class); + + if ($this->user) { + $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); + } else { + $appName = \config('app.name'); + } + + return \trans('mail.' . strtolower($class) . '-subject', ['site' => $appName]); + } +} diff --git a/src/app/Mail/NegativeBalance.php b/src/app/Mail/NegativeBalance.php index 524ed06d..c660fecb 100644 --- a/src/app/Mail/NegativeBalance.php +++ b/src/app/Mail/NegativeBalance.php @@ -1,81 +1,72 @@ wallet = $wallet; $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $subject = \trans('mail.negativebalance-subject', ['site' => $appName]); $this->view('emails.html.negative_balance') ->text('emails.plain.negative_balance') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, 'username' => $this->user->name(true), 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $wallet = new Wallet(); $user = new User(); $mail = new self($wallet, $user); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/NegativeBalanceDegraded.php b/src/app/Mail/NegativeBalanceDegraded.php index e50b3e34..e6042df5 100644 --- a/src/app/Mail/NegativeBalanceDegraded.php +++ b/src/app/Mail/NegativeBalanceDegraded.php @@ -1,82 +1,73 @@ wallet = $wallet; $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $subject = \trans('mail.negativebalancedegraded-subject', ['site' => $appName]); $this->view('emails.html.negative_balance_degraded') ->text('emails.plain.negative_balance_degraded') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, 'username' => $this->user->name(true), 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $wallet = new Wallet(); $user = new User(); $mail = new self($wallet, $user); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/NegativeBalanceReminderDegrade.php b/src/app/Mail/NegativeBalanceReminderDegrade.php index e634655c..72a52531 100644 --- a/src/app/Mail/NegativeBalanceReminderDegrade.php +++ b/src/app/Mail/NegativeBalanceReminderDegrade.php @@ -1,84 +1,75 @@ wallet = $wallet; $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $threshold = WalletCheck::threshold($this->wallet, WalletCheck::THRESHOLD_DEGRADE); - $subject = \trans('mail.negativebalancereminder-subject', ['site' => $appName]); + $subject = \trans('mail.negativebalancereminderdegrade-subject', ['site' => $appName]); $this->view('emails.html.negative_balance_reminder_degrade') ->text('emails.plain.negative_balance_reminder_degrade') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, 'username' => $this->user->name(true), 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id), 'date' => $threshold->toDateString(), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $wallet = new Wallet(); $user = new User(); $mail = new self($wallet, $user); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/PasswordExpirationReminder.php b/src/app/Mail/PasswordExpirationReminder.php index b6c7bc47..7cdcbd9a 100644 --- a/src/app/Mail/PasswordExpirationReminder.php +++ b/src/app/Mail/PasswordExpirationReminder.php @@ -1,81 +1,92 @@ user = $user; $this->expiresOn = $expiresOn; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $href = Utils::serviceUrl('profile', $this->user->tenant_id); $params = [ 'site' => $appName, 'date' => $this->expiresOn, 'link' => sprintf('%s', $href, $href), 'username' => $this->user->name(true), ]; $this->view('emails.html.password_expiration_reminder') ->text('emails.plain.password_expiration_reminder') ->subject(\trans('mail.passwordexpiration-subject', $params)) ->with($params); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $user = new User([ 'email' => 'test@' . \config('app.domain'), ]); $mail = new self($user, now()->copy()->addDays(14)->toDateString()); return Helper::render($mail, $type); } + + /** + * Returns the mail subject. + * + * @return string Mail subject + */ + public function getSubject(): string + { + if ($this->subject) { + return $this->subject; + } + + $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); + + $params = [ + 'site' => $appName, + 'date' => $this->expiresOn, + ]; + + return \trans('mail.passwordexpiration-subject', $params); + } } diff --git a/src/app/Mail/PasswordReset.php b/src/app/Mail/PasswordReset.php index a773b1a9..43c8846f 100644 --- a/src/app/Mail/PasswordReset.php +++ b/src/app/Mail/PasswordReset.php @@ -1,86 +1,81 @@ code = $code; + $this->user = $this->code->user; } /** * Build the message. * * @return $this */ public function build() { - $appName = Tenant::getConfig($this->code->user->tenant_id, 'app.name'); + $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $href = Utils::serviceUrl( sprintf('/password-reset/%s-%s', $this->code->short_code, $this->code->code), - $this->code->user->tenant_id + $this->user->tenant_id ); $this->view('emails.html.password_reset') ->text('emails.plain.password_reset') ->subject(\trans('mail.passwordreset-subject', ['site' => $appName])) ->with([ 'site' => $appName, 'code' => $this->code->code, 'short_code' => $this->code->short_code, 'link' => sprintf('%s', $href, $href), - 'username' => $this->code->user->name(true) + 'username' => $this->user->name(true) ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $code = new VerificationCode([ 'code' => Str::random(VerificationCode::CODE_LENGTH), 'short_code' => VerificationCode::generateShortCode(), ]); // @phpstan-ignore-next-line $code->user = new User([ 'email' => 'test@' . \config('app.domain'), ]); $mail = new self($code); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/PaymentFailure.php b/src/app/Mail/PaymentFailure.php index b77b1971..28b7dc81 100644 --- a/src/app/Mail/PaymentFailure.php +++ b/src/app/Mail/PaymentFailure.php @@ -1,83 +1,74 @@ payment = $payment; $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $subject = \trans('mail.paymentfailure-subject', ['site' => $appName]); $this->view('emails.html.payment_failure') ->text('emails.plain.payment_failure') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, 'username' => $this->user->name(true), 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id), 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'mail'): string { $payment = new Payment(); $user = new User([ 'email' => 'test@' . \config('app.domain'), ]); $mail = new self($payment, $user); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/PaymentMandateDisabled.php b/src/app/Mail/PaymentMandateDisabled.php index c5e97042..6a1e62f6 100644 --- a/src/app/Mail/PaymentMandateDisabled.php +++ b/src/app/Mail/PaymentMandateDisabled.php @@ -1,83 +1,74 @@ wallet = $wallet; $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $subject = \trans('mail.paymentmandatedisabled-subject', ['site' => $appName]); $this->view('emails.html.payment_mandate_disabled') ->text('emails.plain.payment_mandate_disabled') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, 'username' => $this->user->name(true), 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id), 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $wallet = new Wallet(); $user = new User([ 'email' => 'test@' . \config('app.domain'), ]); $mail = new self($wallet, $user); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/PaymentSuccess.php b/src/app/Mail/PaymentSuccess.php index 4616ca94..c7e4675b 100644 --- a/src/app/Mail/PaymentSuccess.php +++ b/src/app/Mail/PaymentSuccess.php @@ -1,83 +1,74 @@ payment = $payment; $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $subject = \trans('mail.paymentsuccess-subject', ['site' => $appName]); $this->view('emails.html.payment_success') ->text('emails.plain.payment_success') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, 'username' => $this->user->name(true), 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id), 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $payment = new Payment(); $user = new User([ 'email' => 'test@' . \config('app.domain'), ]); $mail = new self($payment, $user); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/SignupInvitation.php b/src/app/Mail/SignupInvitation.php index 217ad34e..de196a4c 100644 --- a/src/app/Mail/SignupInvitation.php +++ b/src/app/Mail/SignupInvitation.php @@ -1,75 +1,69 @@ invitation = $invitation; } /** * Build the message. * * @return $this */ public function build() { $appName = Tenant::getConfig($this->invitation->tenant_id, 'app.name'); $href = Utils::serviceUrl('/signup/invite/' . $this->invitation->id, $this->invitation->tenant_id); $this->view('emails.html.signup_invitation') ->text('emails.plain.signup_invitation') ->subject(\trans('mail.signupinvitation-subject', ['site' => $appName])) ->with([ 'site' => $appName, 'href' => $href, ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $invitation = new SI([ 'email' => 'test@external.org', ]); $invitation->id = Utils::uuidStr(); $mail = new self($invitation); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/SignupVerification.php b/src/app/Mail/SignupVerification.php index be3dd9df..24f4ec25 100644 --- a/src/app/Mail/SignupVerification.php +++ b/src/app/Mail/SignupVerification.php @@ -1,85 +1,79 @@ code = $code; } /** * Build the message. * * @return $this */ public function build() { $href = Utils::serviceUrl( sprintf('/signup/%s-%s', $this->code->short_code, $this->code->code) ); $username = $this->code->first_name ?? ''; if (!empty($this->code->last_name)) { $username .= ' ' . $this->code->last_name; } $username = trim($username); - $this->view('emails.html.signup_code') - ->text('emails.plain.signup_code') - ->subject(\trans('mail.signupcode-subject', ['site' => \config('app.name')])) + $this->view('emails.html.signup_verification') + ->text('emails.plain.signup_verification') + ->subject(\trans('mail.signupverification-subject', ['site' => \config('app.name')])) ->with([ 'site' => \config('app.name'), 'username' => $username ?: 'User', 'code' => $this->code->code, 'short_code' => $this->code->short_code, 'href' => $href, ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $code = new SignupCode([ 'code' => Str::random(SignupCode::CODE_LENGTH), 'short_code' => SignupCode::generateShortCode(), 'email' => 'test@' . \config('app.domain'), 'first_name' => 'Firstname', 'last_name' => 'Lastname', ]); $mail = new self($code); return Helper::render($mail, $type); } } diff --git a/src/app/Mail/TrialEnd.php b/src/app/Mail/TrialEnd.php index d0eaff1b..df90cd56 100644 --- a/src/app/Mail/TrialEnd.php +++ b/src/app/Mail/TrialEnd.php @@ -1,75 +1,65 @@ account = $account; + $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { - $appName = Tenant::getConfig($this->account->tenant_id, 'app.name'); - $paymentUrl = Tenant::getConfig($this->account->tenant_id, 'app.kb.payment_system'); - $supportUrl = Tenant::getConfig($this->account->tenant_id, 'app.support_url'); + $appName = Tenant::getConfig($this->user->tenant_id, 'app.name'); + $paymentUrl = Tenant::getConfig($this->user->tenant_id, 'app.kb.payment_system'); + $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url'); $subject = \trans('mail.trialend-subject', ['site' => $appName]); $this->view('emails.html.trial_end') ->text('emails.plain.trial_end') ->subject($subject) ->with([ 'site' => $appName, 'subject' => $subject, - 'username' => $this->account->name(true), + 'username' => $this->user->name(true), 'paymentUrl' => $paymentUrl, - 'supportUrl' => Utils::serviceUrl($supportUrl, $this->account->tenant_id), + 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id), ]); return $this; } /** * Render the mail template with fake data * * @param string $type Output format ('html' or 'text') * * @return string HTML or Plain Text output */ public static function fakeRender(string $type = 'html'): string { $user = new User(); $mail = new self($user); return Helper::render($mail, $type); } } diff --git a/src/resources/lang/en/app.php b/src/resources/lang/en/app.php index 4e99f621..94948894 100644 --- a/src/resources/lang/en/app.php +++ b/src/resources/lang/en/app.php @@ -1,177 +1,178 @@ 'Created', 'chart-deleted' => 'Deleted', 'chart-average' => 'average', 'chart-allusers' => 'All Users - last year', 'chart-discounts' => 'Discounts', 'chart-vouchers' => 'Vouchers', 'chart-income' => 'Income in :currency - last 8 weeks', 'chart-payers' => 'Payers - last year', 'chart-users' => 'Users - last 8 weeks', 'companion-create-success' => 'Companion app has been created.', 'companion-delete-success' => 'Companion app has been removed.', 'event-suspended' => 'Suspended', 'event-unsuspended' => 'Unsuspended', 'event-comment' => 'Commented', + 'event-mailsent' => 'Mail Sent', 'mandate-delete-success' => 'The auto-payment has been removed.', 'mandate-update-success' => 'The auto-payment has been updated.', 'mandate-description-suffix' => 'Auto-Payment Setup', 'planbutton' => 'Choose :plan', 'process-async' => 'Setup process has been pushed. Please wait.', 'process-user-new' => 'Registering a user...', 'process-user-ldap-ready' => 'Creating a user...', 'process-user-imap-ready' => 'Creating a mailbox...', 'process-domain-new' => 'Registering a custom domain...', 'process-domain-ldap-ready' => 'Creating a custom domain...', 'process-domain-verified' => 'Verifying a custom domain...', 'process-domain-confirmed' => 'Confirming an ownership of a custom domain...', 'process-success' => 'Setup process finished successfully.', 'process-error-distlist-ldap-ready' => 'Failed to create a distribution list.', 'process-error-domain-ldap-ready' => 'Failed to create a domain.', 'process-error-domain-verified' => 'Failed to verify a domain.', 'process-error-domain-confirmed' => 'Failed to confirm an ownership of a domain.', 'process-error-resource-imap-ready' => 'Failed to verify that a shared folder exists.', 'process-error-resource-ldap-ready' => 'Failed to create a resource.', 'process-error-shared-folder-imap-ready' => 'Failed to verify that a shared folder exists.', 'process-error-shared-folder-ldap-ready' => 'Failed to create a shared folder.', 'process-error-user-ldap-ready' => 'Failed to create a user.', 'process-error-user-imap-ready' => 'Failed to verify that a mailbox exists.', 'process-distlist-new' => 'Registering a distribution list...', 'process-distlist-ldap-ready' => 'Creating a distribution list...', 'process-resource-new' => 'Registering a resource...', 'process-resource-imap-ready' => 'Creating a shared folder...', 'process-resource-ldap-ready' => 'Creating a resource...', 'process-shared-folder-new' => 'Registering a shared folder...', 'process-shared-folder-imap-ready' => 'Creating a shared folder...', 'process-shared-folder-ldap-ready' => 'Creating a shared folder...', 'discount-code' => 'Discount: :code', 'distlist-update-success' => 'Distribution list updated successfully.', 'distlist-create-success' => 'Distribution list created successfully.', 'distlist-delete-success' => 'Distribution list deleted successfully.', 'distlist-suspend-success' => 'Distribution list suspended successfully.', 'distlist-unsuspend-success' => 'Distribution list unsuspended successfully.', 'distlist-setconfig-success' => 'Distribution list settings updated successfully.', 'domain-create-success' => 'Domain created successfully.', 'domain-delete-success' => 'Domain deleted successfully.', 'domain-notempty-error' => 'Unable to delete a domain with assigned users or other objects.', 'domain-confirm-success' => 'Domain ownership confirmed successfully.', 'domain-confirm-error' => 'Domain ownership confirmation failed.', 'domain-suspend-success' => 'Domain suspended successfully.', 'domain-unsuspend-success' => 'Domain unsuspended successfully.', 'domain-setconfig-success' => 'Domain settings updated successfully.', 'file-create-success' => 'File created successfully.', 'file-delete-success' => 'File deleted successfully.', 'file-update-success' => 'File updated successfully.', 'file-permissions-create-success' => 'File permissions created successfully.', 'file-permissions-update-success' => 'File permissions updated successfully.', 'file-permissions-delete-success' => 'File permissions deleted successfully.', 'collection-create-success' => 'Collection created successfully.', 'collection-delete-success' => 'Collection deleted successfully.', 'collection-update-success' => 'Collection updated successfully.', 'payment-status-paid' => 'The payment has been completed successfully.', 'payment-status-canceled' => 'The payment has been canceled.', 'payment-status-failed' => 'The payment failed.', 'payment-status-expired' => 'The payment expired.', 'payment-status-checking' => "The payment hasn't been completed yet. Checking the status...", 'period-year' => 'year', 'period-month' => 'month', 'resource-update-success' => 'Resource updated successfully.', 'resource-create-success' => 'Resource created successfully.', 'resource-delete-success' => 'Resource deleted successfully.', 'resource-setconfig-success' => 'Resource settings updated successfully.', 'room-update-success' => 'Room updated successfully.', 'room-create-success' => 'Room created successfully.', 'room-delete-success' => 'Room deleted successfully.', 'room-setconfig-success' => 'Room configuration updated successfully.', 'room-unsupported-option-error' => 'Invalid room configuration option.', 'shared-folder-update-success' => 'Shared folder updated successfully.', 'shared-folder-create-success' => 'Shared folder created successfully.', 'shared-folder-delete-success' => 'Shared folder deleted successfully.', 'shared-folder-setconfig-success' => 'Shared folder settings updated successfully.', 'user-update-success' => 'User data updated successfully.', 'user-create-success' => 'User created successfully.', 'user-delete-success' => 'User deleted successfully.', 'user-resync-success' => 'User synchronization has been started.', 'user-suspend-success' => 'User suspended successfully.', 'user-unsuspend-success' => 'User unsuspended successfully.', 'user-reset-2fa-success' => '2-Factor authentication reset successfully.', 'user-reset-geo-lock-success' => 'Geo-lockin setup reset successfully.', 'user-setconfig-success' => 'User settings updated successfully.', 'user-set-sku-success' => 'The subscription added successfully.', 'user-set-sku-already-exists' => 'The subscription already exists.', 'search-foundxdomains' => ':x domains have been found.', 'search-foundxdistlists' => ':x distribution lists have been found.', 'search-foundxresources' => ':x resources have been found.', 'search-foundxshared-folders' => ':x shared folders have been found.', 'search-foundxusers' => ':x user accounts have been found.', 'signup-account-mandate' => 'Now it is required to provide your credit card details.' . ' This way you agree to charge you with an appropriate amount of money according to the plan you signed up for.', 'signup-account-free' => 'You are signing up for an account with 100% discount. You will be redirected immediately to your Dashboard.', 'signup-plan-monthly' => 'You are choosing a monthly subscription.', 'signup-plan-yearly' => 'You are choosing a yearly subscription.', 'signup-subscription-monthly' => 'Monthly subscription', 'signup-subscription-yearly' => 'Yearly subscription', 'signup-invitations-created' => 'The invitation has been created.|:count invitations has been created.', 'signup-invitations-csv-empty' => 'Failed to find any valid email addresses in the uploaded file.', 'signup-invitations-csv-invalid-email' => 'Found an invalid email address (:email) on line :line.', 'signup-invitation-delete-success' => 'Invitation deleted successfully.', 'signup-invitation-resend-success' => 'Invitation added to the sending queue successfully.', 'support-request-success' => 'Support request submitted successfully.', 'support-request-error' => 'Failed to submit the support request.', 'siteuser' => ':site User', 'total' => 'Total', 'wallet-award-success' => 'The bonus has been added to the wallet successfully.', 'wallet-penalty-success' => 'The penalty has been added to the wallet successfully.', 'wallet-update-success' => 'User wallet updated successfully.', 'password-reset-code-delete-success' => 'Password reset code deleted successfully.', 'password-rule-min' => 'Minimum password length: :param characters', 'password-rule-max' => 'Maximum password length: :param characters', 'password-rule-lower' => 'Password contains a lower-case character', 'password-rule-upper' => 'Password contains an upper-case character', 'password-rule-digit' => 'Password contains a digit', 'password-rule-special' => 'Password contains a special character', 'password-rule-last' => 'Password cannot be the same as the last :param passwords', 'wallet-notice-date' => 'With your current subscriptions your account balance will last until about :date (:days).', 'wallet-notice-nocredit' => 'You are out of credit, top up your balance now.', 'wallet-notice-today' => 'You will run out of credit today, top up your balance now.', 'wallet-notice-trial' => 'You are in your free trial period.', 'wallet-notice-trial-end' => 'Your free trial is about to end, top up to continue.', 'vat-incl' => 'Incl. VAT :vat (:rate of :cost)', ]; diff --git a/src/resources/lang/en/mail.php b/src/resources/lang/en/mail.php index 62a3fc80..87c5ae9a 100644 --- a/src/resources/lang/en/mail.php +++ b/src/resources/lang/en/mail.php @@ -1,102 +1,102 @@ "Dear :name,", 'footer1' => "Best regards,", 'footer2' => "Your :site Team", 'more-info-html' => "See here for more information.", 'more-info-text' => "See :href for more information.", 'degradedaccountreminder-subject' => ":site Reminder: Your account is free", 'degradedaccountreminder-body1' => "Thanks for sticking around, we remind you your account is a free " . "account and restricted to receiving email, and use of the web client and cockpit only.", 'degradedaccountreminder-body2' => "This leaves you with an ideal account to use for account registration with third parties " . "and password resets, notifications or even just subscriptions to newsletters and the like.", 'degradedaccountreminder-body3' => "To regain functionality such as sending email, calendars, address books, phone synchronization " . "and voice & video conferencing, log on to the cockpit and make sure you have a positive account balance.", 'degradedaccountreminder-body4' => "You can also delete your account there, making sure your data disappears from our systems.", 'degradedaccountreminder-body5' => "Thank you for your consideration!", 'negativebalance-subject' => ":site Payment Required", 'negativebalance-body' => "This is a notification to let you know that your :site account balance has run into the negative and requires your attention. " . "Consider setting up an automatic payment to avoid messages like this in the future.", 'negativebalance-body-ext' => "Settle up to keep your account running:", - 'negativebalancereminder-subject' => ":site Payment Reminder", - 'negativebalancereminder-body' => "It has probably skipped your attention that you are behind on paying for your :site account. " + 'negativebalancereminderdegrade-subject' => ":site Payment Reminder", + 'negativebalancereminderdegrade-body' => "It has probably skipped your attention that you are behind on paying for your :site account. " . "Consider setting up an automatic payment to avoid messages like this in the future.", - 'negativebalancereminder-body-ext' => "Settle up to keep your account running:", + 'negativebalancereminderdegrade-body-ext' => "Settle up to keep your account running:", 'negativebalancereminderdegrade-body-warning' => "Please, be aware that your account will be degraded " . "if your account balance is not settled by :date.", 'negativebalancedegraded-subject' => ":site Account Degraded", 'negativebalancedegraded-body' => "Your :site account has been degraded for having a negative balance for too long. " . "Consider setting up an automatic payment to avoid messages like this in the future.", 'negativebalancedegraded-body-ext' => "Settle up now to undegrade your account:", 'passwordreset-subject' => ":site Password Reset", 'passwordreset-body1' => "Someone recently asked to change your :site password.", 'passwordreset-body2' => "If this was you, use this verification code to complete the process:", 'passwordreset-body3' => "You can also click the link below:", 'passwordreset-body4' => "If you did not make such a request, you can either ignore this message or get in touch with us about this incident.", 'passwordexpiration-subject' => ":site password expires on :date", 'passwordexpiration-body' => "Your password will expire on :date. You can change it here:", 'paymentmandatedisabled-subject' => ":site Auto-payment Problem", 'paymentmandatedisabled-body' => "Your :site account balance is negative " . "and the configured amount for automatically topping up the balance does not cover " . "the costs of subscriptions consumed.", 'paymentmandatedisabled-body-ext' => "Charging you multiple times for the same amount in short succession " . "could lead to issues with the payment provider. " . "In order to not cause any problems, we suspended auto-payment for your account. " . "To resolve this issue, login to your account settings and adjust your auto-payment amount.", 'paymentfailure-subject' => ":site Payment Failed", 'paymentfailure-body' => "Something went wrong with auto-payment for your :site account.\n" . "We tried to charge you via your preferred payment method, but the charge did not go through.", 'paymentfailure-body-ext' => "In order to not cause any further issues, we suspended auto-payment for your account. " . "To resolve this issue, login to your account settings at", 'paymentfailure-body-rest' => "There you can pay manually for your account and " . "change your auto-payment settings.", 'paymentsuccess-subject' => ":site Payment Succeeded", 'paymentsuccess-body' => "The auto-payment for your :site account went through without issues. " . "You can check your new account balance and more details here:", 'support' => "Special circumstances? Something is wrong with a charge?\n" . ":site Support is here to help.", - 'signupcode-subject' => ":site Registration", - 'signupcode-body1' => "This is your verification code for the :site registration process:", - 'signupcode-body2' => "You can also click the link below to continue the registration process:", + 'signupverification-subject' => ":site Registration", + 'signupverification-body1' => "This is your verification code for the :site registration process:", + 'signupverification-body2' => "You can also click the link below to continue the registration process:", 'signupinvitation-subject' => ":site Invitation", 'signupinvitation-header' => "Hi,", 'signupinvitation-body1' => "You have been invited to join :site. Click the link below to sign up.", 'signupinvitation-body2' => "", 'trialend-subject' => ":site: Your trial phase has ended", 'trialend-intro' => "We hope you enjoyed the 30 days of free :site trial." . " Your subscriptions become active after the first month of use and the fee is due after another month.", 'trialend-kb' => "You can read about how to pay the subscription fee in this knowledge base article:", 'trialend-body1' => "You can leave :site at any time, there is no contractual minimum period" . " and your account will NOT be deleted automatically." . " You can delete your account via the red [Delete account] button in your profile." . " This will end your subscription and delete all relevant data.", 'trialend-body2' => "THIS OPERATION IS IRREVERSIBLE!", 'trialend-body3' => "When data is deleted it can not be recovered." . " Please make sure that you have saved all data that you need before pressing the red button." . " Do not hesitate to contact Support with any questions or concerns.", ]; diff --git a/src/resources/lang/fr/mail.php b/src/resources/lang/fr/mail.php index 59fe8da1..2fb95199 100644 --- a/src/resources/lang/fr/mail.php +++ b/src/resources/lang/fr/mail.php @@ -1,87 +1,87 @@ "Salut :name,", 'footer1' => "Meilleures salutations,", 'footer2' => "Votre :site Équipe", 'more-info-html' => "Cliquez ici pour plus d'information.", 'more-info-text' => "Cliquez :href pour plus d'information.", 'degradedaccountreminder-subject' => "Rappel du :site: Votre compte est gratuit", 'degradedaccountreminder-body1' => "Merci de ne pas quitter le site, nous vous rappelons que votre compte est gratuit." . " et limité à la réception d'emails, et à l'utilisation du client web et du cockpit uniquement.", 'degradedaccountreminder-body2' => "Vous disposez ainsi d'un compte idéal à employer pour l'enregistrement de comptes auprès de tiers" . " et les réinitialisations de mot de passe, les notifications ou même simplement les souscriptions aux newsletters et autres.", 'degradedaccountreminder-body3' => "Pour récupérer les fonctionnalités telles que l'envoi de e-mail, les calendriers, les carnets d'adresses et la synchronisation des téléphones" . " et les voix et vidéoconférences, connectez-vous au cockpit et assurez-vous que le solde de votre compte est positif.", 'degradedaccountreminder-body4' => "Vous pouvez également y supprimer votre compte, afin que vos données disparaissent de nos systèmes.", 'degradedaccountreminder-body5' => "Nous apprécions votre collaboration!", 'negativebalance-subject' => ":site Paiement Requis", 'negativebalance-body' => "C'est une notification pour vous informer que votre :site le solde du compte est en négatif et nécessite votre attention." . " Veillez à mettre en place un auto-paiement pour éviter de tel avertissement comme celui-ci dans le future.", 'negativebalance-body-ext' => "Régler votre compte pour le maintenir en fontion:", - 'negativebalancereminder-subject' => ":site Rappel de Paiement", - 'negativebalancereminder-body' => "Vous n'avez peut-être pas rendu compte que vous êtes en retard avec votre paiement pour :site compte." + 'negativebalancereminderdegrade-subject' => ":site Rappel de Paiement", + 'negativebalancereminderdegrade-body' => "Vous n'avez peut-être pas rendu compte que vous êtes en retard avec votre paiement pour :site compte." . " Veillez à mettre en place un auto-paiement pour éviter de tel avertissement comme celui-ci dans le future.", - 'negativebalancereminder-body-ext' => "Régler votre compte pour le maintenir en fontion:", + 'negativebalancereminderdegrade-body-ext' => "Régler votre compte pour le maintenir en fontion:", 'negativebalancereminderdegrade-body-warning' => "Veuillez noter que votre compte sera dégradé" . " si le solde de votre compte n'est pas réglé avant le :date.", 'negativebalancedegraded-subject' => ":site de Compte Dégradé", 'negativebalancedegraded-body' => "Votre compte :site a été dégradé pour avoir un solde négatif depuis trop longtemps." . " Envisagez de mettre en place un paiement automatique pour éviter des messages comme celui-ci à l'avenir.", 'negativebalancedegraded-body-ext' => "Réglez maintenant pour rétablir votre compte:", 'passwordreset-subject' => ":site Réinitialisation du mot de passe", 'passwordreset-body1' => "Quelqu'un a récemment demandé de changer votre :site mot de passe.", 'passwordreset-body2' => "Si vous êtes dans ce cas, veuillez utiliser ce code de vérification pour terminer le processus:", 'passwordreset-body3' => "Vous pourrez également cliquer sur le lien ci-dessous:", 'passwordreset-body4' => "si vous n'avez pas fait une telle demande, vous pouvez soit ignorer ce message, soit prendre contact avec nous au sujet de cet incident.", 'paymentmandatedisabled-subject' => ":site Problème d'auto-paiement", 'paymentmandatedisabled-body' => "Votre :site solde du compte est négatif" . " et le montant configuré pour le rechargement automatique du solde ne suffit pas" . " le coût des abonnements consommés.", 'paymentmandatedisabled-body-ext' => "En vous facturant plusieurs fois le même monant dans un court laps de temps" . " peut entraîner des problêmes avec le fournisseur du service de paiement." . " Pour éviter tout problème, nous avons suspendu l'auto-paiement pour votre compte." . " Pour resourdre le problème,veuillez vous connecter aux paramètres de votre compte et modifier le montant d'auto-paiement.", 'paymentfailure-subject' => ":site Paiement Echoué", 'paymentfailure-body' => "Un problème est survenu avec l'auto-paiement pour votre :site account.\n" . "Nous avons tenté de vous facturer via votre méthode de paiement choisie, mais le chargement n'a pas été effectué.", 'paymentfailure-body-ext' => "Pour éviter tout problème supplémentaire, nous avons suspendu l'auto-paiement sur votre compte." . " Pour resourdre le problème,veuillez vous connecter aux paramètres de votre compte au", 'paymentfailure-body-rest' => "Vous y trouverez la possibilité de payer manuellement votre compte et" . " de modifier vos paramètres d'auto-paiement.", 'paymentsuccess-subject' => ":site Paiement Effectué", 'paymentsuccess-body' => "L'auto-paiement pour votre :site le compte s'est exécuté sans problème. " . "Vous pouvez contrôler le solde de votre nouveau compte et obtenir plus de détails ici:", 'support' => "Cas particulier? Il y a un probléme avec une charge?\n" . ":site Le support reste à votre disposition.", - 'signupcode-subject' => ":site Enregistrement", - 'signupcode-body1' => "Voici votre code de vérification pour le :site registration process:", - 'signupcode-body2' => "Vous pouvez également continuer avec le processus d'enregistrement en cliquant sur le lien ci-dessous:", + 'signupverification-subject' => ":site Enregistrement", + 'signupverification-body1' => "Voici votre code de vérification pour le :site registration process:", + 'signupverification-body2' => "Vous pouvez également continuer avec le processus d'enregistrement en cliquant sur le lien ci-dessous:", 'signupinvitation-subject' => ":site Invitation", 'signupinvitation-header' => "Salut,", 'signupinvitation-body1' => "Vous êtes invité à joindre :site. Cliquez sur le lien ci-dessous pour vous inscrire.", 'signupinvitation-body2' => "", ]; diff --git a/src/resources/views/emails/html/negative_balance_reminder_degrade.blade.php b/src/resources/views/emails/html/negative_balance_reminder_degrade.blade.php index 80f7cb04..8c4ea0f8 100644 --- a/src/resources/views/emails/html/negative_balance_reminder_degrade.blade.php +++ b/src/resources/views/emails/html/negative_balance_reminder_degrade.blade.php @@ -1,22 +1,22 @@

{{ __('mail.header', ['name' => $username]) }}

-

{{ __('mail.negativebalancereminder-body', ['site' => $site]) }}

-

{{ __('mail.negativebalancereminder-body-ext', ['site' => $site]) }}

+

{{ __('mail.negativebalancereminderdegrade-body', ['site' => $site]) }}

+

{{ __('mail.negativebalancereminderdegrade-body-ext', ['site' => $site]) }}

{{ $walletUrl }}

{{ __('mail.negativebalancereminderdegrade-body-warning', ['site' => $site, 'date' => $date]) }}

@if ($supportUrl)

{{ __('mail.support', ['site' => $site]) }}

{{ $supportUrl }}

@endif

{{ __('mail.footer1') }}

{{ __('mail.footer2', ['site' => $site]) }}

diff --git a/src/resources/views/emails/html/signup_code.blade.php b/src/resources/views/emails/html/signup_verification.blade.php similarity index 76% rename from src/resources/views/emails/html/signup_code.blade.php rename to src/resources/views/emails/html/signup_verification.blade.php index b582a128..3e7bbd2c 100644 --- a/src/resources/views/emails/html/signup_code.blade.php +++ b/src/resources/views/emails/html/signup_verification.blade.php @@ -1,20 +1,20 @@

{{ __('mail.header', ['name' => $username]) }}

-

{{ __('mail.signupcode-body1', ['site' => $site]) }}

+

{{ __('mail.signupverification-body1', ['site' => $site]) }}

{!! $short_code !!}

-

{{ __('mail.signupcode-body2') }}

+

{{ __('mail.signupverification-body2') }}

{!! $href !!}

{{ __('mail.footer1') }}

{{ __('mail.footer2', ['site' => $site]) }}

diff --git a/src/resources/views/emails/plain/negative_balance_reminder_degrade.blade.php b/src/resources/views/emails/plain/negative_balance_reminder_degrade.blade.php index 01a9d312..54686789 100644 --- a/src/resources/views/emails/plain/negative_balance_reminder_degrade.blade.php +++ b/src/resources/views/emails/plain/negative_balance_reminder_degrade.blade.php @@ -1,19 +1,19 @@ {!! __('mail.header', ['name' => $username]) !!} -{!! __('mail.negativebalancereminder-body', ['site' => $site]) !!} +{!! __('mail.negativebalancereminderdegrade-body', ['site' => $site]) !!} -{!! __('mail.negativebalancereminder-body-ext', ['site' => $site]) !!} +{!! __('mail.negativebalancereminderdegrade-body-ext', ['site' => $site]) !!} {!! $walletUrl !!} {!! __('mail.negativebalancereminderdegrade-body-warning', ['site' => $site, 'date' => $date]) !!} @if ($supportUrl) {!! __('mail.support', ['site' => $site]) !!} {!! $supportUrl !!} @endif -- {!! __('mail.footer1') !!} {!! __('mail.footer2', ['site' => $site]) !!} diff --git a/src/resources/views/emails/plain/signup_code.blade.php b/src/resources/views/emails/plain/signup_verification.blade.php similarity index 60% rename from src/resources/views/emails/plain/signup_code.blade.php rename to src/resources/views/emails/plain/signup_verification.blade.php index 0ccb2a94..cacfe750 100644 --- a/src/resources/views/emails/plain/signup_code.blade.php +++ b/src/resources/views/emails/plain/signup_verification.blade.php @@ -1,13 +1,13 @@ {!! __('mail.header', ['name' => $username]) !!} -{!! __('mail.signupcode-body1', ['site' => $site]) !!} +{!! __('mail.signupverification-body1', ['site' => $site]) !!} {!! $short_code !!} -{!! __('mail.signupcode-body2') !!} +{!! __('mail.signupverification-body2') !!} {!! $href !!} -- {!! __('mail.footer1') !!} {!! __('mail.footer2', ['site' => $site]) !!} diff --git a/src/tests/Unit/Mail/DegradedAccountReminderTest.php b/src/tests/Unit/Mail/DegradedAccountReminderTest.php index f598e92b..32de908c 100644 --- a/src/tests/Unit/Mail/DegradedAccountReminderTest.php +++ b/src/tests/Unit/Mail/DegradedAccountReminderTest.php @@ -1,42 +1,57 @@ getTestUser('ned@kolab.org'); $wallet = $user->wallets->first(); $mail = $this->renderMail(new DegradedAccountReminder($wallet, $user)); $html = $mail['html']; $plain = $mail['plain']; $dashboardUrl = \App\Utils::serviceUrl('/dashboard'); $dashboardLink = sprintf('%s', $dashboardUrl, $dashboardUrl); $appName = $user->tenant->title; $this->assertSame("$appName Reminder: Your account is free", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $dashboardLink) > 0); $this->assertTrue(strpos($html, "your account is a free account") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $dashboardUrl) > 0); $this->assertTrue(strpos($plain, "your account is a free account") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = $this->getTestUser('ned@kolab.org'); + $wallet = $user->wallets->first(); + $appName = $user->tenant->title; + + $mail = new DegradedAccountReminder($wallet, $user); + + $this->assertSame("$appName Reminder: Your account is free", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/HelperTest.php b/src/tests/Unit/Mail/HelperTest.php index 8a027160..42ec8e16 100644 --- a/src/tests/Unit/Mail/HelperTest.php +++ b/src/tests/Unit/Mail/HelperTest.php @@ -1,164 +1,179 @@ deleteTestUser('mail-helper-test@kolabnow.com'); \App\TenantSetting::truncate(); } /** * {@inheritDoc} */ public function tearDown(): void { $this->deleteTestUser('mail-helper-test@kolabnow.com'); \App\TenantSetting::truncate(); parent::tearDown(); } /** * Test Helper::sendMail() */ public function testSendMail(): void { + EventLog::truncate(); Mail::fake(); $tenant = \App\Tenant::whereNotIn('id', [1])->first(); $invitation = new \App\SignupInvitation(); $invitation->id = 'test'; $mail = new \App\Mail\SignupInvitation($invitation); Helper::sendMail($mail, null, ['to' => 'to@test.com', 'cc' => 'cc@test.com']); Mail::assertSent(\App\Mail\SignupInvitation::class, 1); Mail::assertSent(\App\Mail\SignupInvitation::class, function ($mail) { return $mail->hasTo('to@test.com') && $mail->hasCc('cc@test.com') && $mail->hasFrom(\config('mail.from.address'), \config('mail.from.name')) && $mail->hasReplyTo(\config('mail.reply_to.address'), \config('mail.reply_to.name')); }); // Test with a tenant (but no per-tenant settings) Mail::fake(); $invitation->tenant_id = $tenant->id; $mail = new \App\Mail\SignupInvitation($invitation); Helper::sendMail($mail, $tenant->id, ['to' => 'to@test.com', 'cc' => 'cc@test.com']); Mail::assertSent(\App\Mail\SignupInvitation::class, 1); Mail::assertSent(\App\Mail\SignupInvitation::class, function ($mail) { return $mail->hasTo('to@test.com') && $mail->hasCc('cc@test.com') && $mail->hasFrom(\config('mail.from.address'), \config('mail.from.name')) && $mail->hasReplyTo(\config('mail.reply_to.address'), \config('mail.reply_to.name')); }); // Test with a tenant (but with per-tenant settings) Mail::fake(); $tenant->setSettings([ 'mail.from.address' => 'from@test.com', 'mail.from.name' => 'from name', 'mail.reply_to.address' => 'replyto@test.com', 'mail.reply_to.name' => 'replyto name', ]); $mail = new \App\Mail\SignupInvitation($invitation); Helper::sendMail($mail, $tenant->id, ['to' => 'to@test.com']); Mail::assertSent(\App\Mail\SignupInvitation::class, 1); Mail::assertSent(\App\Mail\SignupInvitation::class, function ($mail) { return $mail->hasTo('to@test.com') && $mail->hasFrom('from@test.com', 'from name') && $mail->hasReplyTo('replyto@test.com', 'replyto name'); }); - // TODO: Test somehow log entries, maybe with timacdonald/log-fake package + // No EventLog entries up to this point + $this->assertSame(0, EventLog::count()); + + // Assert EventLog entry + $user = $this->getTestUser('mail-helper-test@kolabnow.com'); + $mail = new \App\Mail\TrialEnd($user); + + Helper::sendMail($mail, $tenant->id, ['to' => 'to@test.com', 'cc' => 'cc@test.com']); + + $event = EventLog::where('object_id', $user->id)->where('object_type', User::class)->first(); + $this->assertSame(EventLog::TYPE_MAILSENT, $event->type); + $this->assertSame(['recipients' => ['to@test.com', 'cc@test.com']], $event->data); + $this->assertSame("[TrialEnd] Kolab Now: Your trial phase has ended", $event->comment); + // TODO: Test somehow exception case } /** * Test Helper::userEmails() */ public function testUserEmails(): void { $status = User::STATUS_ACTIVE | User::STATUS_LDAP_READY | User::STATUS_IMAP_READY; $user = $this->getTestUser('mail-helper-test@kolabnow.com', ['status' => $status]); // User with no mailbox and no external email list($to, $cc) = Helper::userEmails($user); $this->assertSame(null, $to); $this->assertSame([], $cc); list($to, $cc) = Helper::userEmails($user, true); $this->assertSame(null, $to); $this->assertSame([], $cc); // User with no mailbox but with external email $user->setSetting('external_email', 'external@test.com'); list($to, $cc) = Helper::userEmails($user); $this->assertSame('external@test.com', $to); $this->assertSame([], $cc); list($to, $cc) = Helper::userEmails($user, true); $this->assertSame('external@test.com', $to); $this->assertSame([], $cc); // User with mailbox and external email $sku = \App\Sku::withEnvTenantContext()->where('title', 'mailbox')->first(); $user->assignSku($sku); list($to, $cc) = Helper::userEmails($user); $this->assertSame($user->email, $to); $this->assertSame([], $cc); list($to, $cc) = Helper::userEmails($user, true); $this->assertSame($user->email, $to); $this->assertSame(['external@test.com'], $cc); // User with mailbox, but no external email $user->setSetting('external_email', null); list($to, $cc) = Helper::userEmails($user); $this->assertSame($user->email, $to); $this->assertSame([], $cc); list($to, $cc) = Helper::userEmails($user, true); $this->assertSame($user->email, $to); $this->assertSame([], $cc); // Use with mailbox, but not ready $user->setSetting('external_email', 'external@test.com'); $user->status = User::STATUS_ACTIVE | User::STATUS_LDAP_READY; $user->save(); list($to, $cc) = Helper::userEmails($user, true); $this->assertSame(null, $to); $this->assertSame(['external@test.com'], $cc); } } diff --git a/src/tests/Unit/Mail/NegativeBalanceDegradedTest.php b/src/tests/Unit/Mail/NegativeBalanceDegradedTest.php index fd498db8..c848564b 100644 --- a/src/tests/Unit/Mail/NegativeBalanceDegradedTest.php +++ b/src/tests/Unit/Mail/NegativeBalanceDegradedTest.php @@ -1,55 +1,70 @@ getTestUser('ned@kolab.org'); $wallet = $user->wallets->first(); $wallet->balance = -100; $wallet->save(); \config([ 'app.support_url' => 'https://kolab.org/support', ]); $mail = $this->renderMail(new NegativeBalanceDegraded($wallet, $user)); $html = $mail['html']; $plain = $mail['plain']; $walletUrl = \App\Utils::serviceUrl('/wallet'); $walletLink = sprintf('%s', $walletUrl, $walletUrl); $supportUrl = \config('app.support_url'); $supportLink = sprintf('%s', $supportUrl, $supportUrl); $appName = $user->tenant->title; $this->assertSame("$appName Account Degraded", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $walletLink) > 0); $this->assertTrue(strpos($html, $supportLink) > 0); $this->assertTrue(strpos($html, "Your $appName account has been degraded") > 0); $this->assertTrue(strpos($html, "$appName Support") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $walletUrl) > 0); $this->assertTrue(strpos($plain, $supportUrl) > 0); $this->assertTrue(strpos($plain, "Your $appName account has been degraded") > 0); $this->assertTrue(strpos($plain, "$appName Support") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = $this->getTestUser('ned@kolab.org'); + $wallet = $user->wallets->first(); + $appName = $user->tenant->title; + + $mail = new NegativeBalanceDegraded($wallet, $user); + + $this->assertSame("$appName Account Degraded", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/NegativeBalanceReminderDegradeTest.php b/src/tests/Unit/Mail/NegativeBalanceReminderDegradeTest.php index f2d319da..242668bf 100644 --- a/src/tests/Unit/Mail/NegativeBalanceReminderDegradeTest.php +++ b/src/tests/Unit/Mail/NegativeBalanceReminderDegradeTest.php @@ -1,61 +1,76 @@ getTestUser('ned@kolab.org'); $wallet = $user->wallets->first(); $wallet->balance = -100; $wallet->save(); $threshold = WalletCheck::threshold($wallet, WalletCheck::THRESHOLD_DEGRADE); \config([ 'app.support_url' => 'https://kolab.org/support', ]); $mail = $this->renderMail(new NegativeBalanceReminderDegrade($wallet, $user)); $html = $mail['html']; $plain = $mail['plain']; $walletUrl = \App\Utils::serviceUrl('/wallet'); $walletLink = sprintf('%s', $walletUrl, $walletUrl); $supportUrl = \config('app.support_url'); $supportLink = sprintf('%s', $supportUrl, $supportUrl); $appName = $user->tenant->title; $this->assertSame("$appName Payment Reminder", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $walletLink) > 0); $this->assertTrue(strpos($html, $supportLink) > 0); $this->assertTrue(strpos($html, "you are behind on paying for your $appName account") > 0); $this->assertTrue(strpos($html, "your account will be degraded") > 0); $this->assertTrue(strpos($html, $threshold->toDateString()) > 0); $this->assertTrue(strpos($html, "$appName Support") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $walletUrl) > 0); $this->assertTrue(strpos($plain, $supportUrl) > 0); $this->assertTrue(strpos($plain, "you are behind on paying for your $appName account") > 0); $this->assertTrue(strpos($plain, "your account will be degraded") > 0); $this->assertTrue(strpos($plain, $threshold->toDateString()) > 0); $this->assertTrue(strpos($plain, "$appName Support") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = $this->getTestUser('ned@kolab.org'); + $wallet = $user->wallets->first(); + $appName = $user->tenant->title; + + $mail = new NegativeBalanceReminderDegrade($wallet, $user); + + $this->assertSame("$appName Payment Reminder", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/NegativeBalanceTest.php b/src/tests/Unit/Mail/NegativeBalanceTest.php index 842cd356..d449b1ee 100644 --- a/src/tests/Unit/Mail/NegativeBalanceTest.php +++ b/src/tests/Unit/Mail/NegativeBalanceTest.php @@ -1,52 +1,67 @@ 'https://kolab.org/support', ]); $mail = $this->renderMail(new NegativeBalance($wallet, $user)); $html = $mail['html']; $plain = $mail['plain']; $walletUrl = \App\Utils::serviceUrl('/wallet'); $walletLink = sprintf('%s', $walletUrl, $walletUrl); $supportUrl = \config('app.support_url'); $supportLink = sprintf('%s', $supportUrl, $supportUrl); $appName = \config('app.name'); $this->assertSame("$appName Payment Required", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $walletLink) > 0); $this->assertTrue(strpos($html, $supportLink) > 0); $this->assertTrue(strpos($html, "your $appName account balance has run into the nega") > 0); $this->assertTrue(strpos($html, "$appName Support") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $walletUrl) > 0); $this->assertTrue(strpos($plain, $supportUrl) > 0); $this->assertTrue(strpos($plain, "your $appName account balance has run into the nega") > 0); $this->assertTrue(strpos($plain, "$appName Support") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = new User(); + $wallet = new Wallet(); + $appName = \config('app.name'); + + $mail = new NegativeBalance($wallet, $user); + + $this->assertSame("$appName Payment Required", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/PasswordExpirationReminderTest.php b/src/tests/Unit/Mail/PasswordExpirationReminderTest.php index f1de1086..c49cdafc 100644 --- a/src/tests/Unit/Mail/PasswordExpirationReminderTest.php +++ b/src/tests/Unit/Mail/PasswordExpirationReminderTest.php @@ -1,43 +1,58 @@ 'User Name', ]); $expiresOn = now()->copy()->addDays(7)->toDateString(); $mail = $this->renderMail(new PasswordExpirationReminder($user, $expiresOn)); $html = $mail['html']; $plain = $mail['plain']; $url = Utils::serviceUrl('profile'); $link = "$url"; $appName = \config('app.name'); $this->assertSame("$appName password expires on $expiresOn", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $link) > 0); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $expiresOn) > 0); $this->assertStringStartsWith("Dear " . $user->name(true), $plain); $this->assertTrue(strpos($plain, $link) > 0); $this->assertTrue(strpos($plain, $expiresOn) > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = new User(['name' => 'User Name']); + $appName = \config('app.name'); + $expiresOn = now()->copy()->addDays(7)->toDateString(); + + $mail = new PasswordExpirationReminder($user, $expiresOn); + + $this->assertSame("$appName password expires on $expiresOn", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/PasswordResetTest.php b/src/tests/Unit/Mail/PasswordResetTest.php index ddc5554b..d871f27b 100644 --- a/src/tests/Unit/Mail/PasswordResetTest.php +++ b/src/tests/Unit/Mail/PasswordResetTest.php @@ -1,48 +1,70 @@ 123456789, 'mode' => 'password-reset', 'code' => 'code', 'short_code' => 'short-code', ]); // @phpstan-ignore-next-line $code->user = new User([ 'name' => 'User Name', ]); $mail = $this->renderMail(new PasswordReset($code)); $html = $mail['html']; $plain = $mail['plain']; $url = Utils::serviceUrl('/password-reset/' . $code->short_code . '-' . $code->code); $link = "$url"; $appName = \config('app.name'); $this->assertSame("$appName Password Reset", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $link) > 0); $this->assertTrue(strpos($html, $code->user->name(true)) > 0); $this->assertStringStartsWith("Dear " . $code->user->name(true), $plain); $this->assertTrue(strpos($plain, $link) > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $appName = \config('app.name'); + $code = new VerificationCode([ + 'user_id' => 123456789, + 'mode' => 'password-reset', + 'code' => 'code', + 'short_code' => 'short-code', + ]); + + // @phpstan-ignore-next-line + $code->user = new User(['name' => 'User Name']); + + $mail = new PasswordReset($code); + + $this->assertSame("$appName Password Reset", $mail->getSubject()); + $this->assertSame($code->user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/PaymentFailureTest.php b/src/tests/Unit/Mail/PaymentFailureTest.php index 255d0ebf..a7e0a1bf 100644 --- a/src/tests/Unit/Mail/PaymentFailureTest.php +++ b/src/tests/Unit/Mail/PaymentFailureTest.php @@ -1,51 +1,68 @@ amount = 123; \config(['app.support_url' => 'https://kolab.org/support']); $mail = $this->renderMail(new PaymentFailure($payment, $user)); $html = $mail['html']; $plain = $mail['plain']; $walletUrl = \App\Utils::serviceUrl('/wallet'); $walletLink = sprintf('%s', $walletUrl, $walletUrl); $supportUrl = \config('app.support_url'); $supportLink = sprintf('%s', $supportUrl, $supportUrl); $appName = \config('app.name'); $this->assertSame("$appName Payment Failed", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $walletLink) > 0); $this->assertTrue(strpos($html, $supportLink) > 0); $this->assertTrue(strpos($html, "$appName Support") > 0); $this->assertTrue(strpos($html, "Something went wrong with auto-payment for your $appName account") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $walletUrl) > 0); $this->assertTrue(strpos($plain, $supportUrl) > 0); $this->assertTrue(strpos($plain, "$appName Support") > 0); $this->assertTrue(strpos($plain, "Something went wrong with auto-payment for your $appName account") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = new User(); + $user->id = 1234; + $payment = new Payment(); + $payment->amount = 123; + $appName = \config('app.name'); + + $mail = new PaymentFailure($payment, $user); + + $this->assertSame("$appName Payment Failed", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/PaymentMandateDisabledTest.php b/src/tests/Unit/Mail/PaymentMandateDisabledTest.php index 0c1ca4cf..0ccdef04 100644 --- a/src/tests/Unit/Mail/PaymentMandateDisabledTest.php +++ b/src/tests/Unit/Mail/PaymentMandateDisabledTest.php @@ -1,50 +1,66 @@ 'https://kolab.org/support']); $mail = $this->renderMail(new PaymentMandateDisabled($wallet, $user)); $html = $mail['html']; $plain = $mail['plain']; $walletUrl = \App\Utils::serviceUrl('/wallet'); $walletLink = sprintf('%s', $walletUrl, $walletUrl); $supportUrl = \config('app.support_url'); $supportLink = sprintf('%s', $supportUrl, $supportUrl); $appName = \config('app.name'); $this->assertSame("$appName Auto-payment Problem", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $walletLink) > 0); $this->assertTrue(strpos($html, $supportLink) > 0); $this->assertTrue(strpos($html, "$appName Support") > 0); $this->assertTrue(strpos($html, "Your $appName account balance") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $walletUrl) > 0); $this->assertTrue(strpos($plain, $supportUrl) > 0); $this->assertTrue(strpos($plain, "$appName Support") > 0); $this->assertTrue(strpos($plain, "Your $appName account balance") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = new User(); + $user->id = 1234; + $wallet = new Wallet(); + $appName = \config('app.name'); + + $mail = new PaymentMandateDisabled($wallet, $user); + + $this->assertSame("$appName Auto-payment Problem", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/PaymentSuccessTest.php b/src/tests/Unit/Mail/PaymentSuccessTest.php index e219c515..5daa3f06 100644 --- a/src/tests/Unit/Mail/PaymentSuccessTest.php +++ b/src/tests/Unit/Mail/PaymentSuccessTest.php @@ -1,51 +1,68 @@ amount = 123; \config(['app.support_url' => 'https://kolab.org/support']); $mail = $this->renderMail(new PaymentSuccess($payment, $user)); $html = $mail['html']; $plain = $mail['plain']; $walletUrl = \App\Utils::serviceUrl('/wallet'); $walletLink = sprintf('%s', $walletUrl, $walletUrl); $supportUrl = \config('app.support_url'); $supportLink = sprintf('%s', $supportUrl, $supportUrl); $appName = \config('app.name'); $this->assertSame("$appName Payment Succeeded", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $walletLink) > 0); $this->assertTrue(strpos($html, $supportLink) > 0); $this->assertTrue(strpos($html, "$appName Support") > 0); $this->assertTrue(strpos($html, "The auto-payment for your $appName account") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $walletUrl) > 0); $this->assertTrue(strpos($plain, $supportUrl) > 0); $this->assertTrue(strpos($plain, "$appName Support") > 0); $this->assertTrue(strpos($plain, "The auto-payment for your $appName account") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = new User(); + $user->id = 1234; + $payment = new Payment(); + $payment->amount = 123; + $appName = \config('app.name'); + + $mail = new PaymentSuccess($payment, $user); + + $this->assertSame("$appName Payment Succeeded", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/SignupInvitationTest.php b/src/tests/Unit/Mail/SignupInvitationTest.php index 36a18b3e..15f2bc93 100644 --- a/src/tests/Unit/Mail/SignupInvitationTest.php +++ b/src/tests/Unit/Mail/SignupInvitationTest.php @@ -1,41 +1,58 @@ 'abc', 'email' => 'test@email', ]); $mail = $this->renderMail(new SignupInvitation($invitation)); $html = $mail['html']; $plain = $mail['plain']; $url = Utils::serviceUrl('/signup/invite/' . $invitation->id); $link = "$url"; $appName = \config('app.name'); $this->assertSame("$appName Invitation", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $link) > 0); $this->assertTrue(strpos($html, "invited to join $appName") > 0); $this->assertStringStartsWith("Hi,", $plain); $this->assertTrue(strpos($plain, "invited to join $appName") > 0); $this->assertTrue(strpos($plain, $url) > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $appName = \config('app.name'); + $invitation = new SI([ + 'id' => 'abc', + 'email' => 'test@email', + ]); + + $mail = new SignupInvitation($invitation); + + $this->assertSame("$appName Invitation", $mail->getSubject()); + $this->assertSame(null, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/SignupVerificationTest.php b/src/tests/Unit/Mail/SignupVerificationTest.php index 9cbea0b8..c2a46ebf 100644 --- a/src/tests/Unit/Mail/SignupVerificationTest.php +++ b/src/tests/Unit/Mail/SignupVerificationTest.php @@ -1,43 +1,63 @@ 'code', 'short_code' => 'short-code', 'email' => 'test@email', 'first_name' => 'First', 'last_name' => 'Last', ]); $mail = $this->renderMail(new SignupVerification($code)); $html = $mail['html']; $plain = $mail['plain']; $url = Utils::serviceUrl('/signup/' . $code->short_code . '-' . $code->code); $link = "$url"; $appName = \config('app.name'); $this->assertSame("$appName Registration", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $link) > 0); $this->assertTrue(strpos($html, 'First Last') > 0); $this->assertStringStartsWith('Dear First Last', $plain); $this->assertTrue(strpos($plain, $url) > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $appName = \config('app.name'); + $code = new SignupCode([ + 'code' => 'code', + 'short_code' => 'short-code', + 'email' => 'test@email', + 'first_name' => 'First', + 'last_name' => 'Last', + ]); + + $mail = new SignupVerification($code); + + $this->assertSame("$appName Registration", $mail->getSubject()); + $this->assertSame(null, $mail->getUser()); + } } diff --git a/src/tests/Unit/Mail/TrialEndTest.php b/src/tests/Unit/Mail/TrialEndTest.php index c275ea0d..c9458f86 100644 --- a/src/tests/Unit/Mail/TrialEndTest.php +++ b/src/tests/Unit/Mail/TrialEndTest.php @@ -1,49 +1,63 @@ 'https://kolab.org/support', 'app.kb.payment_system' => 'https://kb.kolab.org/payment-system', ]); $mail = $this->renderMail(new TrialEnd($user)); $html = $mail['html']; $plain = $mail['plain']; $supportUrl = \config('app.support_url'); $supportLink = sprintf('%s', $supportUrl, $supportUrl); $paymentUrl = \config('app.kb.payment_system'); $paymentLink = sprintf('%s', $paymentUrl, $paymentUrl); $appName = \config('app.name'); $this->assertSame("$appName: Your trial phase has ended", $mail['subject']); $this->assertStringStartsWith('', $html); $this->assertTrue(strpos($html, $user->name(true)) > 0); $this->assertTrue(strpos($html, $supportLink) > 0); $this->assertTrue(strpos($html, $paymentLink) > 0); $this->assertTrue(strpos($html, "30 days of free $appName trial") > 0); $this->assertTrue(strpos($html, "$appName Team") > 0); $this->assertStringStartsWith('Dear ' . $user->name(true), $plain); $this->assertTrue(strpos($plain, $supportUrl) > 0); $this->assertTrue(strpos($plain, $paymentUrl) > 0); $this->assertTrue(strpos($plain, "30 days of free $appName trial") > 0); $this->assertTrue(strpos($plain, "$appName Team") > 0); } + + /** + * Test getSubject() and getUser() + */ + public function testGetSubjectAndUser(): void + { + $user = new User(); + $appName = \config('app.name'); + + $mail = new TrialEnd($user); + + $this->assertSame("$appName: Your trial phase has ended", $mail->getSubject()); + $this->assertSame($user, $mail->getUser()); + } }