Add tests for featured thumbnail generation; apply Pint formatting and related edits
This commit is contained in:
@@ -4,11 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Academy;
|
||||
|
||||
use App\Models\AcademyAiComparisonResult;
|
||||
use App\Models\AcademyChallenge;
|
||||
use App\Models\AcademyLesson;
|
||||
use App\Models\AcademyLessonBlock;
|
||||
use App\Models\AcademyPromptPack;
|
||||
use App\Models\AcademyPromptTemplate;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final class AcademyAccessService
|
||||
@@ -66,6 +69,7 @@ final class AcademyAccessService
|
||||
'access_level' => (string) $lesson->access_level,
|
||||
'lesson_type' => (string) $lesson->lesson_type,
|
||||
'cover_image' => $lesson->cover_image,
|
||||
'cover_image_url' => $this->resolveLessonCoverImageUrl((string) ($lesson->cover_image ?? '')),
|
||||
'video_url' => $authorized ? $lesson->video_url : null,
|
||||
'reading_minutes' => (int) $lesson->reading_minutes,
|
||||
'featured' => (bool) $lesson->featured,
|
||||
@@ -76,6 +80,9 @@ final class AcademyAccessService
|
||||
'name' => (string) $lesson->category->name,
|
||||
'slug' => (string) $lesson->category->slug,
|
||||
] : null,
|
||||
'blocks' => ($authorized && $includeFull)
|
||||
? $lesson->activeBlocks->map(fn (AcademyLessonBlock $block): ?array => $this->lessonBlockPayload($block))->filter()->values()->all()
|
||||
: [],
|
||||
'locked' => ! $authorized,
|
||||
'can_access' => $authorized,
|
||||
];
|
||||
@@ -100,7 +107,7 @@ final class AcademyAccessService
|
||||
'aspect_ratio' => $prompt->aspect_ratio,
|
||||
'tags' => array_values((array) ($prompt->tags ?? [])),
|
||||
'tool_notes' => $authorized ? (array) ($prompt->tool_notes ?? []) : [],
|
||||
'preview_image' => $prompt->preview_image,
|
||||
'preview_image' => $this->resolvePreviewImageUrl((string) ($prompt->preview_image ?? '')),
|
||||
'featured' => (bool) $prompt->featured,
|
||||
'prompt_of_week' => (bool) $prompt->prompt_of_week,
|
||||
'published_at' => $prompt->published_at?->toISOString(),
|
||||
@@ -204,6 +211,115 @@ final class AcademyAccessService
|
||||
$previewLength = max(1, $length - 1);
|
||||
}
|
||||
|
||||
return rtrim(mb_substr($plain, 0, $previewLength)) . '...';
|
||||
return rtrim(mb_substr($plain, 0, $previewLength)).'...';
|
||||
}
|
||||
}
|
||||
|
||||
private function resolvePreviewImageUrl(string $previewImage): ?string
|
||||
{
|
||||
$previewImage = trim($previewImage);
|
||||
|
||||
if ($previewImage === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str_starts_with($previewImage, 'http://') || str_starts_with($previewImage, 'https://') || str_starts_with($previewImage, '/')) {
|
||||
return $previewImage;
|
||||
}
|
||||
|
||||
return Storage::disk((string) config('uploads.object_storage.disk', 's3'))->url($previewImage);
|
||||
}
|
||||
|
||||
private function resolveLessonCoverImageUrl(string $coverImage): ?string
|
||||
{
|
||||
$coverImage = trim($coverImage);
|
||||
|
||||
if ($coverImage === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str_starts_with($coverImage, 'http://') || str_starts_with($coverImage, 'https://') || str_starts_with($coverImage, '/')) {
|
||||
return $coverImage;
|
||||
}
|
||||
|
||||
return Storage::disk((string) config('uploads.object_storage.disk', 's3'))->url($coverImage);
|
||||
}
|
||||
|
||||
private function resolveLessonMediaUrl(string $path): ?string
|
||||
{
|
||||
$path = trim($path);
|
||||
|
||||
if ($path === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str_starts_with($path, 'http://') || str_starts_with($path, 'https://') || str_starts_with($path, '/')) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
return Storage::disk((string) config('uploads.object_storage.disk', 's3'))->url($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
private function lessonBlockPayload(AcademyLessonBlock $block): ?array
|
||||
{
|
||||
if ($block->type !== 'ai_comparison') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$payload = is_array($block->payload) ? $block->payload : [];
|
||||
$criteria = collect($payload['criteria'] ?? [])
|
||||
->map(static fn ($criterion): string => trim((string) $criterion))
|
||||
->filter(static fn (string $criterion): bool => $criterion !== '')
|
||||
->values()
|
||||
->all();
|
||||
$results = $block->activeComparisonResults
|
||||
->map(fn (AcademyAiComparisonResult $result): array => [
|
||||
'id' => (int) $result->id,
|
||||
'provider' => (string) ($result->provider ?? ''),
|
||||
'model_name' => (string) ($result->model_name ?? ''),
|
||||
'image_path' => (string) $result->image_path,
|
||||
'image_url' => $this->resolveLessonMediaUrl((string) $result->image_path),
|
||||
'thumb_path' => (string) ($result->thumb_path ?? ''),
|
||||
'thumb_url' => $this->resolveLessonMediaUrl((string) ($result->thumb_path ?? '')),
|
||||
'settings' => (string) ($result->settings ?? ''),
|
||||
'strengths' => (string) ($result->strengths ?? ''),
|
||||
'weaknesses' => (string) ($result->weaknesses ?? ''),
|
||||
'best_for' => (string) ($result->best_for ?? ''),
|
||||
'score' => $result->score,
|
||||
'sort_order' => (int) $result->sort_order,
|
||||
'active' => (bool) $result->active,
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$hasPromptData = filled($payload['prompt'] ?? null)
|
||||
|| filled($payload['negative_prompt'] ?? null)
|
||||
|| filled($payload['intro'] ?? null)
|
||||
|| filled($payload['title'] ?? null)
|
||||
|| filled($payload['aspect_ratio'] ?? null)
|
||||
|| ! empty($criteria);
|
||||
|
||||
if (! $hasPromptData && $results === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (int) $block->id,
|
||||
'type' => (string) $block->type,
|
||||
'title' => (string) ($block->title ?? ($payload['title'] ?? '')),
|
||||
'payload' => [
|
||||
'title' => (string) ($payload['title'] ?? ''),
|
||||
'intro' => (string) ($payload['intro'] ?? ''),
|
||||
'prompt' => (string) ($payload['prompt'] ?? ''),
|
||||
'negative_prompt' => (string) ($payload['negative_prompt'] ?? ''),
|
||||
'aspect_ratio' => (string) ($payload['aspect_ratio'] ?? ''),
|
||||
'criteria' => $criteria,
|
||||
],
|
||||
'sort_order' => (int) $block->sort_order,
|
||||
'active' => (bool) $block->active,
|
||||
'comparison_results' => $results,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user