@using BTCPayServer.Configuration @using BTCPayServer.Contracts @model BTCPayServer.Controllers.ServerController.ListPluginsViewModel @inject BTCPayServerOptions BTCPayServerOptions @{ ViewData.SetActivePageAndTitle(ServerNavPages.Plugins); var installed = Model.Installed.ToDictionary(plugin => plugin.Identifier.ToLowerInvariant(), plugin => plugin.Version); var availableAndNotInstalled = Model.Available.Where(plugin => !installed.ContainsKey(plugin.Identifier.ToLowerInvariant())).Select(plugin => (plugin, BTCPayServerOptions.RecommendedPlugins.Contains(plugin.Identifier.ToLowerInvariant()))).OrderBy(tuple => tuple.Item1); bool DependentOn(string plugin) { foreach (var installedPlugin in Model.Installed) { if (installedPlugin.Dependencies.Any(dep => dep.Identifier.Equals(plugin, StringComparison.InvariantCultureIgnoreCase))) { return true; } } var pendingInstalls = Model.Commands.Where(tuple => tuple.command != "uninstall").Select(tuple => tuple.plugin).Distinct(); foreach (var pendingInstall in pendingInstalls) { if (Model.Available.Any(availablePlugin => availablePlugin.Identifier.Equals(pendingInstall, StringComparison.InvariantCultureIgnoreCase) && availablePlugin.Dependencies.Any(dep => dep.Identifier.Equals(plugin, StringComparison.InvariantCultureIgnoreCase)))) { return true; } } return false; } bool DependencyMet(IBTCPayServerPlugin.PluginDependency dependency) { var plugin = dependency.Identifier.ToLowerInvariant(); var versionReq = dependency.Condition; if (!installed.ContainsKey(plugin) && !versionReq.Equals("!")) { return false; } if (installed.ContainsKey(plugin) && versionReq.Equals("!")) { return false; } var versionConditions = versionReq.Split("||", StringSplitOptions.RemoveEmptyEntries); return versionConditions.Any(s => { s = s.Trim(); var v = s.Substring(1); if (s[1] == '=') { v = s.Substring(2); } var parsedV = Version.Parse(v); switch (s) { case { } xx when xx.StartsWith(">="): return installed[plugin] >= parsedV; case { } xx when xx.StartsWith("<="): return installed[plugin] <= parsedV; case { } xx when xx.StartsWith(">"): return installed[plugin] > parsedV; case { } xx when xx.StartsWith("<"): return installed[plugin] >= parsedV; case { } xx when xx.StartsWith("^"): return installed[plugin] >= parsedV && installed[plugin].Major == parsedV.Major; case { } xx when xx.StartsWith("~"): return installed[plugin] >= parsedV && installed[plugin].Major == parsedV.Major && installed[plugin].Minor == parsedV.Minor; case { } xx when xx.StartsWith("!="): return installed[plugin] != parsedV; case { } xx when xx.StartsWith("=="): default: return installed[plugin] == parsedV; } }); } bool DependenciesMet(IBTCPayServerPlugin.PluginDependency[] dependencies) { foreach (var dependency in dependencies) { if (!DependencyMet(dependency)) { return false; } } return true; } } @if (Model.Commands.Any()) {
You need to restart BTCPay Server in order to update your active plugins. @if (Model.CanShowRestart) {
}
} @if (Model.Installed.Any()) {

Installed Plugins

@foreach (var plugin in Model.Installed) { var matchedAvailable = Model.Available.SingleOrDefault(availablePlugin => availablePlugin.Identifier == plugin.Identifier); var updateAvailable = !plugin.SystemPlugin && matchedAvailable != null && plugin.Version < matchedAvailable.Version; var tabId = plugin.Identifier.ToLowerInvariant().Replace(".", "_");

@plugin.Name

@plugin.Version @if (plugin.SystemPlugin) {
System plugin
} else if (updateAvailable) {
@matchedAvailable.Version available
}
@if (updateAvailable) { Show current version Show update information }

@plugin.Description

@if (plugin.Dependencies.Any()) {
Dependencies
    @foreach (var dependency in plugin.Dependencies) {
  • @dependency @if (!DependencyMet(dependency)) { }
  • }
}
@if (updateAvailable) {

@matchedAvailable.Description

@if (matchedAvailable.Dependencies.Any()) {
Dependencies
    @foreach (var dependency in matchedAvailable.Dependencies) {
  • @dependency @if (!DependencyMet(dependency)) { }
  • }
}
}
@{ var pendingAction = Model.Commands.Any(tuple => tuple.plugin.Equals(plugin.Identifier, StringComparison.InvariantCultureIgnoreCase)); } @if (!plugin.SystemPlugin && (pendingAction || (updateAvailable && DependenciesMet(matchedAvailable.Dependencies)) || !DependentOn(plugin.Identifier))) { }
}
} @if (availableAndNotInstalled.Any()) {

Available Plugins

@foreach (var pluginT in availableAndNotInstalled) { var plugin = pluginT.Item1;

@plugin.Name

@plugin.Version @if (pluginT.Item2) {
Recommended
}

@plugin.Description

@if (plugin.Dependencies?.Any() is true) {
Dependencies
    @foreach (var dependency in plugin.Dependencies) {
  • @dependency @if (!DependencyMet(dependency)) { }
  • }
}
@{ var pending = Model.Commands.Any(tuple => tuple.plugin.Equals(plugin.Identifier, StringComparison.InvariantCultureIgnoreCase)); }
}
}

Add plugin manually

This is an extremely dangerous operation!
Only upload plugins from trusted sources.
@if (Model.Commands.Any()) {

Pending actions

    @foreach (var extComm in Model.Commands.GroupBy(tuple => tuple.plugin)) {
  • @extComm.Key
  • }
} @section Scripts { }