Replace the RSS-2.0-only SimpleXML parser with SimplePie so the Fetch RSS
node reads Atom 1.0 (YouTube, GitHub, The Verge…) and RSS 2.0 + namespace
extensions (dc:, content:, media:, yt:, itunes:). Each item exposes stable
cross-format aliases (title, link, date, content, author, …) plus every
namespaced field flattened for use as {{ fetched.* }}.
Add a feed-inspection endpoint that discovers a feed's real fields and feeds
them into the editor's expression autocomplete. Allow {{ }} expressions in the
feed URL via a ResolvableUrl rule. Parsing moves to a dedicated FeedParser
service; the fetch keeps the SSRF guard and gains XXE-safe parsing.
69 lines
1.8 KiB
PHP
69 lines
1.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Resources\App\Automation;
|
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Resources\Json\JsonResource;
|
|
|
|
/**
|
|
* Flattens the first parsed feed item into a catalog of `{{ fetched.* }}` paths
|
|
* with sample values, so the editor can offer them as expression completions.
|
|
*
|
|
* @property array<string, mixed> $resource The first normalized feed item.
|
|
*/
|
|
class FeedInspectionResource extends JsonResource
|
|
{
|
|
private const SAMPLE_MAX_LENGTH = 120;
|
|
|
|
/**
|
|
* @return array{fields: list<array{path: string, sample: string}>}
|
|
*/
|
|
public function toArray(Request $request): array
|
|
{
|
|
return [
|
|
'fields' => $this->flatten((array) $this->resource),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $item
|
|
* @return list<array{path: string, sample: string}>
|
|
*/
|
|
private function flatten(array $item, string $prefix = 'fetched'): array
|
|
{
|
|
$fields = [];
|
|
|
|
foreach ($item as $key => $value) {
|
|
$path = "{$prefix}.{$key}";
|
|
|
|
if (is_array($value) && $this->isAssoc($value)) {
|
|
$fields = array_merge($fields, $this->flatten($value, $path));
|
|
|
|
continue;
|
|
}
|
|
|
|
$fields[] = ['path' => $path, 'sample' => $this->sample($value)];
|
|
}
|
|
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* @param array<int|string, mixed> $value
|
|
*/
|
|
private function isAssoc(array $value): bool
|
|
{
|
|
return $value !== [] && ! array_is_list($value);
|
|
}
|
|
|
|
private function sample(mixed $value): string
|
|
{
|
|
$text = is_array($value)
|
|
? (json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?: '')
|
|
: (string) $value;
|
|
|
|
return str($text)->squish()->limit(self::SAMPLE_MAX_LENGTH)->value();
|
|
}
|
|
}
|