with(['user']) ->orderBy('created_at', 'desc') ->get(); } public function findById(int $id): ?Media { return Media::with(['user'])->find($id); } public function create(array $data): Media { return Media::create($data); } public function update(int $id, array $data): ?Media { $model = $this->findById($id); if (! $model) { return null; } $model->update($data); return $model->fresh(['user']); } public function delete(int $id): bool { $model = $this->findById($id); if (! $model) { return false; } return $model->delete(); } // public function getPendingProfileMedia(int $page = 1, int $perPage = 10): LengthAwarePaginator { return Media::query() ->where(function ($query) { $query->where(function ($query) { $query->where('media.source', 'provider') ->whereExists(function ($query) { $query->selectRaw('1') ->from('providers') ->whereColumn('providers.id', 'media.source_id') ->whereColumn('providers.profile_media_id', 'media.id') ->where('providers.approval_status', ApprovalStatusEnum::ACCEPTED->value) ->where('providers.selfie_verified', false) ->whereNull('providers.deleted_at'); }); })->orWhere(function ($query) { $query->where('media.source', 'client') ->whereExists(function ($query) { $query->selectRaw('1') ->from('clients') ->whereColumn('clients.id', 'media.source_id') ->whereColumn('clients.profile_media_id', 'media.id') ->where('clients.selfie_verified', false) ->whereNull('clients.deleted_at'); }); }); }) ->orderBy('media.created_at') ->paginate($perPage, ['media.*'], 'page', $page); } public function approveProfileMedia(string $source, int $sourceId): Media { return DB::transaction(function () use ($source, $sourceId) { $profile = match ($source) { 'client' => Client::query()->lockForUpdate()->findOrFail($sourceId), 'provider' => Provider::query()->lockForUpdate()->findOrFail($sourceId), }; $profile->load('profileMedia'); $media = $profile->profileMedia; if ($media === null) { throw (new ModelNotFoundException)->setModel(Media::class); } $profile->update(['selfie_verified' => true]); return $media; }); } public function createFromFile(UploadedFile $file, string $folder, string $source, int $sourceId, ?string $filename = null): Media { Log::warning('[avatar-upload] MediaService::createFromFile — iniciando upload para S3', [ 'folder' => $folder, 'source' => $source, 'source_id' => $sourceId, 'file_original_name' => $file->getClientOriginalName(), 'file_size' => $file->getSize(), 'file_mime' => $file->getMimeType(), 'file_extension' => $file->getClientOriginalExtension(), 'file_is_valid' => $file->isValid(), ]); $path = $this->uploadFile($file, $folder, $filename); Log::warning('[avatar-upload] MediaService::createFromFile — upload concluído, criando registro Media', [ 'path_retornado' => $path, 'source' => $source, 'source_id' => $sourceId, ]); $media = Media::create([ 'source' => $source, 'source_id' => $sourceId, 'name' => $file->getClientOriginalName(), 'path' => $path, ]); Log::warning('[avatar-upload] MediaService::createFromFile — Media criado no banco', [ 'media_id' => $media->id, 'media_path' => $media->path, 'media_url' => $media->url ?? null, ]); return $media; } public function replaceFile(UploadedFile $newFile, string $folder, string $source, int $sourceId, ?Media $old = null, ?string $filename = null): Media { Log::warning('[avatar-upload] MediaService::replaceFile iniciado', [ 'folder' => $folder, 'source' => $source, 'source_id' => $sourceId, 'has_old_media' => $old !== null, 'old_media_id' => $old?->id, 'old_path' => $old?->path, ]); if ($old) { Log::warning('[avatar-upload] Removendo arquivo antigo do S3', ['old_path' => $old->path]); $this->removeArchiveByPath($old->path); $old->delete(); Log::warning('[avatar-upload] Arquivo antigo removido do S3 e Media deletado do banco'); } return $this->createFromFile($newFile, $folder, $source, $sourceId, $filename); } }