trypost/app/Rules/ContentFitsPlatformLimits.php
Paulo Castellano 953be22b5b fix(posts): block scheduling when content exceeds any platform's char limit
Threads posts over 500 chars were saved + scheduled successfully and only
failed inside the publish job. The frontend already showed the 537|500 badge
but `canSchedule` ignored content length, so Schedule and Post Now stayed
enabled. Backend `UpdatePostRequest` only capped at 63206 (Facebook's max),
not per-platform.

- Add `Platform::contentOverflow()` as the single source of truth and reuse it
  from `HasSocialHttpClient::validateContentLength` (publish-time).
- New `ContentFitsPlatformLimits` rule applied to the `content` field on
  `App\\UpdatePostRequest`, `Api\\UpdatePostRequest`, and `Api\\StorePostRequest`
  via `Rule::when(...)` so drafts are not blocked.
- Rule dedupes per platform (two Threads accounts -> one error) and reports
  the platform label, hard cap, and overage via i18n.
- Edit.vue feeds `contentLengthOverflows` into `canSchedule` and lists each
  offending platform in `postActionTooltip` using the existing
  `getPlatformLabel` resolver.
2026-05-11 19:39:41 -03:00

56 lines
1.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Rules;
use App\Enums\SocialAccount\Platform;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Support\Collection;
use Illuminate\Translation\PotentiallyTranslatedString;
/**
* Fails the content field once per platform whose hard `maxContentLength()` is
* exceeded by the submitted text. Pre-resolve the platforms the post is bound
* to (App: from `post_platforms.id`; API store: from `social_accounts.id`) and
* pass them in — keeps the rule decoupled from the FormRequest payload shape.
*/
class ContentFitsPlatformLimits implements ValidationRule
{
/**
* @param Collection<int|string, Platform> $platforms
*/
public function __construct(private Collection $platforms) {}
/**
* @param Closure(string, ?string=): PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$content = (string) $value;
$reported = [];
foreach ($this->platforms as $platform) {
if (! $platform instanceof Platform) {
continue;
}
if (isset($reported[$platform->value])) {
continue;
}
$over = $platform->contentOverflow($content);
if ($over === null) {
continue;
}
$reported[$platform->value] = true;
$fail(trans('posts.form.content_exceeds_platform', [
'platform' => $platform->label(),
'limit' => $platform->maxContentLength(),
'over' => $over,
]));
}
}
}