wip: article AI polish, category SEO fields, cover generator, membership plan seeder
This commit is contained in:
@@ -4,11 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Domain\Plugin;
|
||||
|
||||
use App\Domain\Blog\ContentRenderer;
|
||||
use App\Models\Plugin;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use InvalidArgumentException;
|
||||
use Mews\Purifier\Facades\Purifier;
|
||||
use RuntimeException;
|
||||
|
||||
class PluginManager
|
||||
@@ -168,7 +170,7 @@ class PluginManager
|
||||
return $dependents;
|
||||
}
|
||||
|
||||
public function docsPath(string $name): ?string
|
||||
public function docsPath(string $name, ?string $locale = null): ?string
|
||||
{
|
||||
$manifest = $this->discover()->get($name);
|
||||
if ($manifest === null) {
|
||||
@@ -181,25 +183,91 @@ class PluginManager
|
||||
}
|
||||
|
||||
$root = realpath((string) $manifest['path']);
|
||||
$path = realpath(rtrim((string) $manifest['path'], '/').'/'.$docs);
|
||||
|
||||
if ($root === false || $path === false || ! is_file($path)) {
|
||||
if ($root === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Never read outside the plugin directory, even via symlinks.
|
||||
if ($path !== $root && ! str_starts_with($path, $root.DIRECTORY_SEPARATOR)) {
|
||||
return null;
|
||||
foreach ($this->docsCandidates($docs, $locale ?? app()->getLocale()) as $relative) {
|
||||
if (str_starts_with($relative, '/') || preg_match('#(^|[\\\\/])\.\.([\\\\/]|$)#', $relative) === 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = realpath($root.DIRECTORY_SEPARATOR.str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $relative));
|
||||
if ($path === false || ! is_file($path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Never read outside the plugin directory, even via symlinks.
|
||||
if ($path !== $root && ! str_starts_with($path, $root.DIRECTORY_SEPARATOR)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
return $path;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function readDocs(string $name): ?string
|
||||
public function readDocs(string $name, ?string $locale = null): ?string
|
||||
{
|
||||
$path = $this->docsPath($name);
|
||||
$path = $this->docsPath($name, $locale);
|
||||
if ($path === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $path !== null ? (string) file_get_contents($path) : null;
|
||||
$contents = (string) file_get_contents($path);
|
||||
|
||||
return trim($contents) === '' ? null : $contents;
|
||||
}
|
||||
|
||||
public function readDocsHtml(string $name, ?string $locale = null): ?string
|
||||
{
|
||||
$markdown = $this->readDocs($name, $locale);
|
||||
if ($markdown === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$html = app(ContentRenderer::class)->markdownToHtml($markdown);
|
||||
|
||||
return Purifier::clean($html, 'article');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer README.{locale}.md, then README.{lang}.md, then the manifest docs file.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
protected function docsCandidates(string $docs, string $locale): array
|
||||
{
|
||||
$docs = str_replace('\\', '/', $docs);
|
||||
$directory = dirname($docs);
|
||||
$basename = basename($docs);
|
||||
$extension = pathinfo($basename, PATHINFO_EXTENSION);
|
||||
$stem = $extension !== ''
|
||||
? substr($basename, 0, -strlen($extension) - 1)
|
||||
: $basename;
|
||||
$suffix = $extension !== '' ? '.'.$extension : '';
|
||||
$prefix = ($directory === '.' || $directory === '') ? '' : $directory.'/';
|
||||
|
||||
$names = [];
|
||||
$normalized = str_replace('-', '_', trim($locale));
|
||||
if ($normalized !== '' && preg_match('/^[A-Za-z0-9_]+$/', $normalized) === 1) {
|
||||
$names[] = $stem.'.'.$normalized.$suffix;
|
||||
if (str_contains($normalized, '_')) {
|
||||
$names[] = $stem.'.'.explode('_', $normalized, 2)[0].$suffix;
|
||||
}
|
||||
}
|
||||
$names[] = $basename;
|
||||
|
||||
$candidates = [];
|
||||
foreach ($names as $name) {
|
||||
$relative = $prefix.$name;
|
||||
if (! in_array($relative, $candidates, true)) {
|
||||
$candidates[] = $relative;
|
||||
}
|
||||
}
|
||||
|
||||
return $candidates;
|
||||
}
|
||||
|
||||
public function registerEnabledProviders(): void
|
||||
|
||||
Reference in New Issue
Block a user