feat(plugins): add minCastopodVersion to denote incompatibility with previous Castopod versions

This commit is contained in:
Yassine Doghri 2024-07-05 16:47:01 +00:00
parent fee7905935
commit fc9ea7597e
8 changed files with 48 additions and 14 deletions

View File

@ -62,6 +62,10 @@ directories should refuse to publish the plugin.
Array of strings to help your plugin get discovered when listed in repositories. Array of strings to help your plugin get discovered when listed in repositories.
### minCastopodVersion
The minimal version of Castopod with which the plugin is compatible.
### hooks ### hooks
List of hooks used by the plugin. If the hook is not specified, Castopod will List of hooks used by the plugin. If the hook is not specified, Castopod will

View File

@ -54,7 +54,16 @@ abstract class BasePlugin implements PluginInterface
$this->manifest = new Manifest($this->key); $this->manifest = new Manifest($this->key);
$this->manifest->loadFromFile($manifestPath); $this->manifest->loadFromFile($manifestPath);
// check compatibility with Castopod version
if ($this->manifest->minCastopodVersion !== null && version_compare(
CP_VERSION,
$this->manifest->minCastopodVersion,
'<'
)) {
$this->status = PluginStatus::INCOMPATIBLE;
} else {
$this->status = get_plugin_setting($this->key, 'active') ? PluginStatus::ACTIVE : PluginStatus::INACTIVE; $this->status = get_plugin_setting($this->key, 'active') ? PluginStatus::ACTIVE : PluginStatus::INACTIVE;
}
$this->iconSrc = $this->loadIcon($directory . '/icon.svg'); $this->iconSrc = $this->loadIcon($directory . '/icon.svg');
@ -214,6 +223,11 @@ abstract class BasePlugin implements PluginInterface
return $settings->{$type}; return $settings->{$type};
} }
final public function getMinCastopodVersion(): string
{
return $this->manifest->minCastopodVersion ?? '';
}
/** /**
* @return list<string> * @return list<string>
*/ */

View File

@ -7,6 +7,7 @@ namespace Modules\Plugins\Core;
enum PluginStatus: string enum PluginStatus: string
{ {
case INVALID = 'invalid'; case INVALID = 'invalid';
case INCOMPATIBLE = 'incompatible';
case INACTIVE = 'inactive'; case INACTIVE = 'inactive';
case ACTIVE = 'active'; case ACTIVE = 'active';
} }

View File

@ -19,8 +19,6 @@ use Modules\Plugins\Config\Plugins as PluginsConfig;
*/ */
class Plugins class Plugins
{ {
public const API_VERSION = '1.0';
/** /**
* @var list<string> * @var list<string>
*/ */

View File

@ -29,6 +29,8 @@ return [
'active' => 'Active', 'active' => 'Active',
'inactive' => 'Inactive', 'inactive' => 'Inactive',
'invalid' => 'Invalid', 'invalid' => 'Invalid',
'incompatible' => 'Incompatible',
'incompatible_hint' => 'Plugin requires Castopod v{minCastopodVersion} minimum.',
'uninstall' => 'Uninstall', 'uninstall' => 'Uninstall',
'keywords' => [ 'keywords' => [
'podcasting20' => 'Podcasting 2.0', 'podcasting20' => 'Podcasting 2.0',

View File

@ -16,6 +16,7 @@ use CodeIgniter\HTTP\URI;
* @property ?string $license * @property ?string $license
* @property bool $private * @property bool $private
* @property list<string> $keywords * @property list<string> $keywords
* @property ?string $minCastopodVersion
* @property list<string> $hooks * @property list<string> $hooks
* @property ?Settings $settings * @property ?Settings $settings
* @property ?Repository $repository * @property ?Repository $repository
@ -34,6 +35,7 @@ class Manifest extends ManifestObject
'license' => 'permit_empty|string', 'license' => 'permit_empty|string',
'private' => 'permit_empty|is_boolean', 'private' => 'permit_empty|is_boolean',
'keywords.*' => 'permit_empty', 'keywords.*' => 'permit_empty',
'minCastopodVersion' => 'permit_empty|regex_match[/^(0|[1-9]\d*)\.(0|[1-9]\d*)(\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/]',
'hooks.*' => 'permit_empty|in_list[rssBeforeChannel,rssAfterChannel,rssBeforeItem,rssAfterItem,siteHead]', 'hooks.*' => 'permit_empty|in_list[rssBeforeChannel,rssAfterChannel,rssBeforeItem,rssAfterItem,siteHead]',
'settings' => 'permit_empty|is_list', 'settings' => 'permit_empty|is_list',
'repository' => 'permit_empty|is_list', 'repository' => 'permit_empty|is_list',
@ -68,6 +70,8 @@ class Manifest extends ManifestObject
*/ */
protected array $keywords = []; protected array $keywords = [];
protected ?string $minCastopodVersion = null;
/** /**
* @var list<string> * @var list<string>
*/ */

View File

@ -83,6 +83,12 @@
}, },
"uniqueItems": true "uniqueItems": true
}, },
"minCastopodVersion": {
"description": "The minimal version of Castopod for which the plugin is compatible with.",
"type": "string",
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$",
"examples": ["2.0"]
},
"hooks": { "hooks": {
"description": "The hooks used by the plugin.", "description": "The hooks used by the plugin.",
"type": "array", "type": "array",

View File

@ -14,6 +14,11 @@ use Modules\Plugins\Core\PluginStatus;
<?php elseif($plugin->getStatus() === PluginStatus::INVALID): ?> <?php elseif($plugin->getStatus() === PluginStatus::INVALID): ?>
<?php // @icon('alert-fill')?> <?php // @icon('alert-fill')?>
<x-Pill variant="warning" icon="alert-fill" class="lowercase" size="small"><?= lang('Plugins.invalid') ?></x-Pill> <x-Pill variant="warning" icon="alert-fill" class="lowercase" size="small"><?= lang('Plugins.invalid') ?></x-Pill>
<?php elseif($plugin->getStatus() === PluginStatus::INCOMPATIBLE): ?>
<?php // @icon('alert-fill')?>
<x-Pill variant="danger" icon="alert-fill" class="lowercase" size="small" hint="<?= lang('Plugins.incompatible_hint', [
'minCastopodVersion' => $plugin->getMinCastopodVersion(),
]) ?>"><?= lang('Plugins.incompatible') ?></x-Pill>
<?php endif; ?> <?php endif; ?>
</div> </div>
<img class="rounded-full min-w-16 max-w-16 aspect-square" src="<?= $plugin->getIconSrc() ?>"> <img class="rounded-full min-w-16 max-w-16 aspect-square" src="<?= $plugin->getIconSrc() ?>">