trypost/app/Mail/PostPublishFailed.php
Paulo Castellano ceb7b92b74 feat: PostPlatform enum, failure email, DB indexes, rate limiting, tests
Publishing improvements:
- Create PostPlatformStatus enum (Pending, Publishing, Published, Failed)
- Update PostPlatform model, jobs, factories to use enum
- Add PostPublishFailed email notification when post fails to publish
- Maizzle template + blade for failure email with platform details
- PublishPost job: add $tries=3, $backoff=30, failed() method
- Fix broadcast event to serialize enum status value

Security:
- Add rate limiting (throttle:6,1) on social connect endpoints
- Fix MediaController::reorder IDOR vulnerability
- Fix Connect.vue broken import (storeStep2 -> storeConnect)
- Fix UpdatePost data_get() consistency

Database:
- Add composite index on post_platforms (post_id, enabled)
- Add index on post_platforms (social_account_id)

Tests:
- Add 3 tests for profile photo upload/delete
- Add 2 tests for media reorder (including IDOR check)
- Fix publish tests for PostPlatformStatus enum
- Add Mail::fake() to publish tests

Cleanup:
- Remove unused AppHeader.vue and AppHeaderLayout.vue
- Remove dead BillingController methods

All 733 tests passing.
2026-03-30 16:11:38 -03:00

61 lines
1.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Mail;
use App\Enums\PostPlatform\Status;
use App\Models\Post;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class PostPublishFailed extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
public function __construct(
public Post $post
) {}
public function envelope(): Envelope
{
return new Envelope(
subject: "Your post failed to publish in {$this->post->workspace->name}",
);
}
public function content(): Content
{
$failedPlatforms = $this->post->postPlatforms()
->with('socialAccount')
->where('enabled', true)
->get()
->filter(fn ($pp) => $pp->status === Status::Failed)
->map(fn ($pp) => [
'name' => $pp->platform->label().' (@'.data_get($pp, 'socialAccount.username', data_get($pp, 'socialAccount.display_name', '')).')',
'error' => $pp->error_message,
])
->values()
->all();
return new Content(
view: 'mail.post-publish-failed',
with: [
'title' => 'Your post failed to publish',
'previewText' => 'One or more platforms failed to publish your post.',
'body' => "Your scheduled post in the {$this->post->workspace->name} workspace failed to publish on one or more platforms.",
'failedPlatforms' => $failedPlatforms,
'url' => route('app.posts.edit', $this->post),
],
);
}
public function attachments(): array
{
return [];
}
}