all system emails look fresh now, plus added paddle portal debugging

This commit is contained in:
Codex Agent
2025-12-23 14:31:42 +01:00
parent 207725d460
commit 1d2c2da915
11 changed files with 394 additions and 12 deletions

View File

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\EventPackageAddon;
use App\Services\Paddle\Exceptions\PaddleException;
use App\Services\Paddle\PaddleCustomerPortalService;
use App\Services\Paddle\PaddleCustomerService;
use App\Services\Paddle\PaddleTransactionService;
@@ -142,13 +143,36 @@ class TenantBillingController extends Controller
], 404);
}
$customerId = null;
try {
$customerId = $this->paddleCustomers->ensureCustomerId($tenant);
Log::debug('Creating Paddle customer portal session', [
'tenant_id' => $tenant->id,
'paddle_customer_id' => $customerId,
'paddle_environment' => config('paddle.environment'),
'paddle_base_url' => config('paddle.base_url'),
]);
$session = $this->portalSessions->createSession($customerId);
} catch (\Throwable $exception) {
Log::warning('Failed to create Paddle customer portal session', [
$context = [
'tenant_id' => $tenant->id,
'paddle_customer_id' => $customerId ?? $tenant->paddle_customer_id,
'error' => $exception->getMessage(),
'paddle_environment' => config('paddle.environment'),
'paddle_base_url' => config('paddle.base_url'),
];
if ($exception instanceof PaddleException) {
$context['paddle_status'] = $exception->status();
$context['paddle_error_code'] = Arr::get($exception->context(), 'error.code');
$context['paddle_error_message'] = Arr::get($exception->context(), 'error.message');
}
Log::warning('Failed to create Paddle customer portal session', [
...$context,
]);
return response()->json([
@@ -162,6 +186,19 @@ class TenantBillingController extends Controller
?? Arr::get($session, 'urls.general');
if (! $url) {
$sessionData = Arr::get($session, 'data');
$sessionUrls = Arr::get($session, 'data.urls') ?? Arr::get($session, 'urls');
Log::warning('Paddle customer portal session missing URL', [
'tenant_id' => $tenant->id,
'paddle_customer_id' => $customerId ?? $tenant->paddle_customer_id,
'paddle_environment' => config('paddle.environment'),
'paddle_base_url' => config('paddle.base_url'),
'session_keys' => array_keys($session),
'session_data_keys' => is_array($sessionData) ? array_keys($sessionData) : null,
'session_url_keys' => is_array($sessionUrls) ? array_keys($sessionUrls) : null,
]);
return response()->json([
'message' => 'Paddle customer portal session missing URL.',
], 502);

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Mail\ContactConfirmation;
use App\Mail\ContactRequest;
use App\Models\BlogPost;
use App\Models\CheckoutSession;
use App\Models\Event;
@@ -74,17 +75,13 @@ class MarketingController extends Controller
}
try {
Mail::raw(
__('emails.contact.body', [
'name' => $request->name,
'email' => $request->email,
'message' => $request->message,
], $locale),
function ($message) use ($contactAddress, $locale) {
$message->to($contactAddress)
->subject(__('emails.contact.subject', [], $locale));
}
);
Mail::to($contactAddress)
->locale($locale)
->send(new ContactRequest(
name: $request->name,
email: $request->email,
messageBody: $request->message,
));
Mail::to($request->email)
->locale($locale)

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class ContactRequest extends Mailable
{
use Queueable, SerializesModels;
public function __construct(
public string $name,
public string $email,
public string $messageBody,
) {}
public function envelope(): Envelope
{
return new Envelope(
subject: __('emails.contact_request.subject'),
replyTo: [new Address($this->email, $this->name)],
);
}
public function content(): Content
{
return new Content(
view: 'emails.contact-request',
with: [
'name' => $this->name,
'email' => $this->email,
'messageBody' => $this->messageBody,
],
);
}
public function attachments(): array
{
return [];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Notifications\ResetPasswordNotification;
use App\Notifications\VerifyEmailNotification;
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasName;
@@ -98,6 +99,11 @@ class User extends Authenticatable implements FilamentHasTenants, FilamentUser,
$this->notify(new VerifyEmailNotification);
}
public function sendPasswordResetNotification($token): void
{
$this->notify(new ResetPasswordNotification($token));
}
protected function fullName(): Attribute
{
return Attribute::make(

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Notifications;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Notifications\Messages\MailMessage;
class ResetPasswordNotification extends ResetPassword
{
public function toMail($notifiable): MailMessage
{
$resetUrl = $this->resetUrl($notifiable);
$expire = (int) config('auth.passwords.'.config('auth.defaults.passwords').'.expire', 60);
return (new MailMessage)
->subject(__('emails.reset_password.subject'))
->view('emails.reset-password', [
'user' => $notifiable,
'resetUrl' => $resetUrl,
'expiresIn' => $expire,
]);
}
}