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.
### minCastopodVersion
The minimal version of Castopod with which the plugin is compatible.
### hooks
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->loadFromFile($manifestPath);
$this->status = get_plugin_setting($this->key, 'active') ? PluginStatus::ACTIVE : PluginStatus::INACTIVE;
// 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->iconSrc = $this->loadIcon($directory . '/icon.svg');
@ -214,6 +223,11 @@ abstract class BasePlugin implements PluginInterface
return $settings->{$type};
}
final public function getMinCastopodVersion(): string
{
return $this->manifest->minCastopodVersion ?? '';
}
/**
* @return list<string>
*/

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@ use CodeIgniter\HTTP\URI;
* @property ?string $license
* @property bool $private
* @property list<string> $keywords
* @property ?string $minCastopodVersion
* @property list<string> $hooks
* @property ?Settings $settings
* @property ?Repository $repository
@ -26,17 +27,18 @@ class Manifest extends ManifestObject
* @var array<string,string>
*/
public const VALIDATION_RULES = [
'name' => 'required|max_length[128]|regex_match[/^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9]([_.-]?[a-z0-9]+)*$/]',
'version' => 'required|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-]+)*))?$/]',
'description' => 'permit_empty|max_length[256]',
'authors' => 'permit_empty|is_list',
'homepage' => 'permit_empty|valid_url_strict',
'license' => 'permit_empty|string',
'private' => 'permit_empty|is_boolean',
'keywords.*' => 'permit_empty',
'hooks.*' => 'permit_empty|in_list[rssBeforeChannel,rssAfterChannel,rssBeforeItem,rssAfterItem,siteHead]',
'settings' => 'permit_empty|is_list',
'repository' => 'permit_empty|is_list',
'name' => 'required|max_length[128]|regex_match[/^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9]([_.-]?[a-z0-9]+)*$/]',
'version' => 'required|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-]+)*))?$/]',
'description' => 'permit_empty|max_length[256]',
'authors' => 'permit_empty|is_list',
'homepage' => 'permit_empty|valid_url_strict',
'license' => 'permit_empty|string',
'private' => 'permit_empty|is_boolean',
'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]',
'settings' => 'permit_empty|is_list',
'repository' => 'permit_empty|is_list',
];
protected const CASTS = [
@ -68,6 +70,8 @@ class Manifest extends ManifestObject
*/
protected array $keywords = [];
protected ?string $minCastopodVersion = null;
/**
* @var list<string>
*/

View File

@ -83,6 +83,12 @@
},
"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": {
"description": "The hooks used by the plugin.",
"type": "array",

View File

@ -14,6 +14,11 @@ use Modules\Plugins\Core\PluginStatus;
<?php elseif($plugin->getStatus() === PluginStatus::INVALID): ?>
<?php // @icon('alert-fill')?>
<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; ?>
</div>
<img class="rounded-full min-w-16 max-w-16 aspect-square" src="<?= $plugin->getIconSrc() ?>">