diff options
| -rw-r--r-- | Jellyfin.Api/Controllers/ItemRefreshController.cs | 89 | ||||
| -rw-r--r-- | Jellyfin.Api/Controllers/LocalizationController.cs | 76 | ||||
| -rw-r--r-- | Jellyfin.Api/Controllers/PluginsController.cs | 189 | ||||
| -rw-r--r-- | Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs | 42 | ||||
| -rw-r--r-- | Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs | 20 | ||||
| -rw-r--r-- | MediaBrowser.Api/ItemRefreshService.cs | 83 | ||||
| -rw-r--r-- | MediaBrowser.Api/LocalizationService.cs | 111 | ||||
| -rw-r--r-- | MediaBrowser.Api/PluginService.cs | 268 |
8 files changed, 416 insertions, 462 deletions
diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs new file mode 100644 index 000000000..d9b8357d2 --- /dev/null +++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs @@ -0,0 +1,89 @@ +#nullable enable +#pragma warning disable CA1801 + +using System.ComponentModel; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.IO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// <summary> + /// Item Refresh Controller. + /// </summary> + /// [Authenticated] + [Route("/Items")] + [Authorize] + public class ItemRefreshController : BaseJellyfinApiController + { + private readonly ILibraryManager _libraryManager; + private readonly IProviderManager _providerManager; + private readonly IFileSystem _fileSystem; + + /// <summary> + /// Initializes a new instance of the <see cref="ItemRefreshController"/> class. + /// </summary> + /// <param name="libraryManager">Instance of <see cref="ILibraryManager"/> interface.</param> + /// <param name="providerManager">Instance of <see cref="IProviderManager"/> interface.</param> + /// <param name="fileSystem">Instance of <see cref="IFileSystem"/> interface.</param> + public ItemRefreshController( + ILibraryManager libraryManager, + IProviderManager providerManager, + IFileSystem fileSystem) + { + _libraryManager = libraryManager; + _providerManager = providerManager; + _fileSystem = fileSystem; + } + + /// <summary> + /// Refreshes metadata for an item. + /// </summary> + /// <param name="id">Item id.</param> + /// <param name="metadataRefreshMode">(Optional) Specifies the metadata refresh mode.</param> + /// <param name="imageRefreshMode">(Optional) Specifies the image refresh mode.</param> + /// <param name="replaceAllMetadata">(Optional) Determines if metadata should be replaced. Only applicable if mode is FullRefresh.</param> + /// <param name="replaceAllImages">(Optional) Determines if images should be replaced. Only applicable if mode is FullRefresh.</param> + /// <param name="recursive">(Unused) Indicates if the refresh should occur recursively.</param> + /// <response code="200">Item metadata refresh queued.</response> + /// <response code="404">Item to refresh not found.</response> + /// <returns>An <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if the item could not be found.</returns> + [HttpPost("{Id}/Refresh")] + [Description("Refreshes metadata for an item.")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public ActionResult Post( + [FromRoute] string id, + [FromQuery] MetadataRefreshMode metadataRefreshMode = MetadataRefreshMode.None, + [FromQuery] MetadataRefreshMode imageRefreshMode = MetadataRefreshMode.None, + [FromQuery] bool replaceAllMetadata = false, + [FromQuery] bool replaceAllImages = false, + [FromQuery] bool recursive = false) + { + var item = _libraryManager.GetItemById(id); + if (item == null) + { + return NotFound(); + } + + var refreshOptions = new MetadataRefreshOptions(new DirectoryService(_fileSystem)) + { + MetadataRefreshMode = metadataRefreshMode, + ImageRefreshMode = imageRefreshMode, + ReplaceAllImages = replaceAllImages, + ReplaceAllMetadata = replaceAllMetadata, + ForceSave = metadataRefreshMode == MetadataRefreshMode.FullRefresh + || imageRefreshMode == MetadataRefreshMode.FullRefresh + || replaceAllImages + || replaceAllMetadata, + IsAutomated = false + }; + + _providerManager.QueueRefresh(item.Id, refreshOptions, RefreshPriority.High); + return Ok(); + } + } +} diff --git a/Jellyfin.Api/Controllers/LocalizationController.cs b/Jellyfin.Api/Controllers/LocalizationController.cs new file mode 100644 index 000000000..1466dd3ec --- /dev/null +++ b/Jellyfin.Api/Controllers/LocalizationController.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using Jellyfin.Api.Constants; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// <summary> + /// Localization controller. + /// </summary> + [Authorize(Policy = Policies.FirstTimeSetupOrElevated)] + public class LocalizationController : BaseJellyfinApiController + { + private readonly ILocalizationManager _localization; + + /// <summary> + /// Initializes a new instance of the <see cref="LocalizationController"/> class. + /// </summary> + /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param> + public LocalizationController(ILocalizationManager localization) + { + _localization = localization; + } + + /// <summary> + /// Gets known cultures. + /// </summary> + /// <response code="200">Known cultures returned.</response> + /// <returns>An <see cref="OkResult"/> containing the list of cultures.</returns> + [HttpGet("Cultures")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<IEnumerable<CultureDto>> GetCultures() + { + return Ok(_localization.GetCultures()); + } + + /// <summary> + /// Gets known countries. + /// </summary> + /// <response code="200">Known countries returned.</response> + /// <returns>An <see cref="OkResult"/> containing the list of countries.</returns> + [HttpGet("Countries")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<IEnumerable<CountryInfo>> GetCountries() + { + return Ok(_localization.GetCountries()); + } + + /// <summary> + /// Gets known parental ratings. + /// </summary> + /// <response code="200">Known parental ratings returned.</response> + /// <returns>An <see cref="OkResult"/> containing the list of parental ratings.</returns> + [HttpGet("ParentalRatings")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<IEnumerable<ParentalRating>> GetParentalRatings() + { + return Ok(_localization.GetParentalRatings()); + } + + /// <summary> + /// Gets localization options. + /// </summary> + /// <response code="200">Localization options returned.</response> + /// <returns>An <see cref="OkResult"/> containing the list of localization options.</returns> + [HttpGet("Options")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult<IEnumerable<LocalizationOption>> GetLocalizationOptions() + { + return Ok(_localization.GetLocalizationOptions()); + } + } +} diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs new file mode 100644 index 000000000..59196a41a --- /dev/null +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -0,0 +1,189 @@ +#nullable enable +#pragma warning disable CA1801 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; +using Jellyfin.Api.Constants; +using Jellyfin.Api.Models.PluginDtos; +using MediaBrowser.Common; +using MediaBrowser.Common.Plugins; +using MediaBrowser.Common.Updates; +using MediaBrowser.Model.Plugins; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace Jellyfin.Api.Controllers +{ + /// <summary> + /// Plugins controller. + /// </summary> + [Authorize] + public class PluginsController : BaseJellyfinApiController + { + private readonly IApplicationHost _appHost; + private readonly IInstallationManager _installationManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PluginsController"/> class. + /// </summary> + /// <param name="appHost">Instance of the <see cref="IApplicationHost"/> interface.</param> + /// <param name="installationManager">Instance of the <see cref="IInstallationManager"/> interface.</param> + public PluginsController( + IApplicationHost appHost, + IInstallationManager installationManager) + { + _appHost = appHost; + _installationManager = installationManager; + } + + /// <summary> + /// Gets a list of currently installed plugins. + /// </summary> + /// <param name="isAppStoreEnabled">Optional. Unused.</param> + /// <response code="200">Installed plugins returned.</response> + /// <returns>List of currently installed plugins.</returns> + [HttpGet] + public ActionResult<IEnumerable<PluginInfo>> GetPlugins([FromRoute] bool? isAppStoreEnabled) + { + return Ok(_appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo())); + } + + /// <summary> + /// Uninstalls a plugin. + /// </summary> + /// <param name="pluginId">Plugin id.</param> + /// <response code="200">Plugin uninstalled.</response> + /// <response code="404">Plugin not found.</response> + /// <returns>An <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns> + [HttpDelete("{pluginId}")] + [Authorize(Policy = Policies.RequiresElevation)] + public ActionResult UninstallPlugin([FromRoute] Guid pluginId) + { + var plugin = _appHost.Plugins.FirstOrDefault(p => p.Id == pluginId); + if (plugin == null) + { + return NotFound(); + } + + _installationManager.UninstallPlugin(plugin); + return Ok(); + } + + /// <summary> + /// Gets plugin configuration. + /// </summary> + /// <param name="pluginId">Plugin id.</param> + /// <response code="200">Plugin configuration returned.</response> + /// <response code="404">Plugin not found or plugin configuration not found.</response> + /// <returns>Plugin configuration.</returns> + [HttpGet("{pluginId}/Configuration")] + public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute] Guid pluginId) + { + if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin)) + { + return NotFound(); + } + + return plugin.Configuration; + } + + /// <summary> + /// Updates plugin configuration. + /// </summary> + /// <remarks> + /// Accepts plugin configuration as JSON body. + /// </remarks> + /// <param name="pluginId">Plugin id.</param> + /// <response code="200">Plugin configuration updated.</response> + /// <response code="200">Plugin not found or plugin does not have configuration.</response> + /// <returns> + /// A <see cref="Task" /> that represents the asynchronous operation to update plugin configuration. + /// The task result contains an <see cref="OkResult"/> indicating success, or <see cref="NotFoundResult"/> + /// when plugin not found or plugin doesn't have configuration. + /// </returns> + [HttpPost("{pluginId}/Configuration")] + public async Task<ActionResult> UpdatePluginConfiguration([FromRoute] Guid pluginId) + { + if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin)) + { + return NotFound(); + } + + var configuration = (BasePluginConfiguration)await JsonSerializer.DeserializeAsync(Request.Body, plugin.ConfigurationType) + .ConfigureAwait(false); + + plugin.UpdateConfiguration(configuration); + return Ok(); + } + + /// <summary> + /// Get plugin security info. + /// </summary> + /// <response code="200">Plugin security info returned.</response> + /// <returns>Plugin security info.</returns> + [Obsolete("This endpoint should not be used.")] + [HttpGet("SecurityInfo")] + public ActionResult<PluginSecurityInfo> GetPluginSecurityInfo() + { + return new PluginSecurityInfo + { + IsMbSupporter = true, + SupporterKey = "IAmTotallyLegit" + }; + } + + /// <summary> + /// Updates plugin security info. + /// </summary> + /// <param name="pluginSecurityInfo">Plugin security info.</param> + /// <response code="200">Plugin security info updated.</response> + /// <returns>An <see cref="OkResult"/>.</returns> + [Obsolete("This endpoint should not be used.")] + [HttpPost("SecurityInfo")] + [Authorize(Policy = Policies.RequiresElevation)] + public ActionResult UpdatePluginSecurityInfo([FromBody, BindRequired] PluginSecurityInfo pluginSecurityInfo) + { + return Ok(); + } + + /// <summary> + /// Gets registration status for a feature. + /// </summary> + /// <param name="name">Feature name.</param> + /// <response code="200">Registration status returned.</response> + /// <returns>Mb registration record.</returns> + [Obsolete("This endpoint should not be used.")] + [HttpPost("RegistrationRecords/{name}")] + public ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute] string name) + { + return new MBRegistrationRecord + { + IsRegistered = true, + RegChecked = true, + TrialVersion = false, + IsValid = true, + RegError = false + }; + } + + /// <summary> + /// Gets registration status for a feature. + /// </summary> + /// <param name="name">Feature name.</param> + /// <response code="501">Not implemented.</response> + /// <returns>Not Implemented.</returns> + /// <exception cref="NotImplementedException">This endpoint is not implemented.</exception> + [Obsolete("Paid plugins are not supported")] + [HttpGet("/Registrations/{name}")] + public ActionResult GetRegistration([FromRoute] string name) + { + // TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins, + // delete all these registration endpoints. They are only kept for compatibility. + throw new NotImplementedException(); + } + } +} diff --git a/Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs b/Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs new file mode 100644 index 000000000..aaaf54267 --- /dev/null +++ b/Jellyfin.Api/Models/PluginDtos/MBRegistrationRecord.cs @@ -0,0 +1,42 @@ +#nullable enable + +using System; + +namespace Jellyfin.Api.Models.PluginDtos +{ + /// <summary> + /// MB Registration Record. + /// </summary> + public class MBRegistrationRecord + { + /// <summary> + /// Gets or sets expiration date. + /// </summary> + public DateTime ExpirationDate { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether is registered. + /// </summary> + public bool IsRegistered { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether reg checked. + /// </summary> + public bool RegChecked { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether reg error. + /// </summary> + public bool RegError { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether trial version. + /// </summary> + public bool TrialVersion { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether is valid. + /// </summary> + public bool IsValid { get; set; } + } +} diff --git a/Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs b/Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs new file mode 100644 index 000000000..793002a6c --- /dev/null +++ b/Jellyfin.Api/Models/PluginDtos/PluginSecurityInfo.cs @@ -0,0 +1,20 @@ +#nullable enable + +namespace Jellyfin.Api.Models.PluginDtos +{ + /// <summary> + /// Plugin security info. + /// </summary> + public class PluginSecurityInfo + { + /// <summary> + /// Gets or sets the supporter key. + /// </summary> + public string? SupporterKey { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether is mb supporter. + /// </summary> + public bool IsMbSupporter { get; set; } + } +} diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs deleted file mode 100644 index 5e86f04a8..000000000 --- a/MediaBrowser.Api/ItemRefreshService.cs +++ /dev/null @@ -1,83 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Api -{ - public class BaseRefreshRequest : IReturnVoid - { - [ApiMember(Name = "MetadataRefreshMode", Description = "Specifies the metadata refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] - public MetadataRefreshMode MetadataRefreshMode { get; set; } - - [ApiMember(Name = "ImageRefreshMode", Description = "Specifies the image refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] - public MetadataRefreshMode ImageRefreshMode { get; set; } - - [ApiMember(Name = "ReplaceAllMetadata", Description = "Determines if metadata should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] - public bool ReplaceAllMetadata { get; set; } - - [ApiMember(Name = "ReplaceAllImages", Description = "Determines if images should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] - public bool ReplaceAllImages { get; set; } - } - - [Route("/Items/{Id}/Refresh", "POST", Summary = "Refreshes metadata for an item")] - public class RefreshItem : BaseRefreshRequest - { - [ApiMember(Name = "Recursive", Description = "Indicates if the refresh should occur recursively.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] - public bool Recursive { get; set; } - - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string Id { get; set; } - } - - [Authenticated] - public class ItemRefreshService : BaseApiService - { - private readonly ILibraryManager _libraryManager; - private readonly IProviderManager _providerManager; - private readonly IFileSystem _fileSystem; - - public ItemRefreshService( - ILogger<ItemRefreshService> logger, - IServerConfigurationManager serverConfigurationManager, - IHttpResultFactory httpResultFactory, - ILibraryManager libraryManager, - IProviderManager providerManager, - IFileSystem fileSystem) - : base(logger, serverConfigurationManager, httpResultFactory) - { - _libraryManager = libraryManager; - _providerManager = providerManager; - _fileSystem = fileSystem; - } - - /// <summary> - /// Posts the specified request. - /// </summary> - /// <param name="request">The request.</param> - public void Post(RefreshItem request) - { - var item = _libraryManager.GetItemById(request.Id); - - var options = GetRefreshOptions(request); - - _providerManager.QueueRefresh(item.Id, options, RefreshPriority.High); - } - - private MetadataRefreshOptions GetRefreshOptions(RefreshItem request) - { - return new MetadataRefreshOptions(new DirectoryService(_fileSystem)) - { - MetadataRefreshMode = request.MetadataRefreshMode, - ImageRefreshMode = request.ImageRefreshMode, - ReplaceAllImages = request.ReplaceAllImages, - ReplaceAllMetadata = request.ReplaceAllMetadata, - ForceSave = request.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || request.ImageRefreshMode == MetadataRefreshMode.FullRefresh || request.ReplaceAllImages || request.ReplaceAllMetadata, - IsAutomated = false - }; - } - } -} diff --git a/MediaBrowser.Api/LocalizationService.cs b/MediaBrowser.Api/LocalizationService.cs deleted file mode 100644 index 6a69d2656..000000000 --- a/MediaBrowser.Api/LocalizationService.cs +++ /dev/null @@ -1,111 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Api -{ - /// <summary> - /// Class GetCultures - /// </summary> - [Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")] - public class GetCultures : IReturn<CultureDto[]> - { - } - - /// <summary> - /// Class GetCountries - /// </summary> - [Route("/Localization/Countries", "GET", Summary = "Gets known countries")] - public class GetCountries : IReturn<CountryInfo[]> - { - } - - /// <summary> - /// Class ParentalRatings - /// </summary> - [Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")] - public class GetParentalRatings : IReturn<ParentalRating[]> - { - } - - /// <summary> - /// Class ParentalRatings - /// </summary> - [Route("/Localization/Options", "GET", Summary = "Gets localization options")] - public class GetLocalizationOptions : IReturn<LocalizationOption[]> - { - } - - /// <summary> - /// Class CulturesService - /// </summary> - [Authenticated(AllowBeforeStartupWizard = true)] - public class LocalizationService : BaseApiService - { - /// <summary> - /// The _localization - /// </summary> - private readonly ILocalizationManager _localization; - - /// <summary> - /// Initializes a new instance of the <see cref="LocalizationService"/> class. - /// </summary> - /// <param name="localization">The localization.</param> - public LocalizationService( - ILogger<LocalizationService> logger, - IServerConfigurationManager serverConfigurationManager, - IHttpResultFactory httpResultFactory, - ILocalizationManager localization) - : base(logger, serverConfigurationManager, httpResultFactory) - { - _localization = localization; - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetParentalRatings request) - { - var result = _localization.GetParentalRatings(); - - return ToOptimizedResult(result); - } - - public object Get(GetLocalizationOptions request) - { - var result = _localization.GetLocalizationOptions(); - - return ToOptimizedResult(result); - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetCountries request) - { - var result = _localization.GetCountries(); - - return ToOptimizedResult(result); - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetCultures request) - { - var result = _localization.GetCultures(); - - return ToOptimizedResult(result); - } - } - -} diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs deleted file mode 100644 index 7f74511ee..000000000 --- a/MediaBrowser.Api/PluginService.cs +++ /dev/null @@ -1,268 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using MediaBrowser.Common; -using MediaBrowser.Common.Plugins; -using MediaBrowser.Common.Updates; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Plugins; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Api -{ - /// <summary> - /// Class Plugins - /// </summary> - [Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")] - [Authenticated] - public class GetPlugins : IReturn<PluginInfo[]> - { - public bool? IsAppStoreEnabled { get; set; } - } - - /// <summary> - /// Class UninstallPlugin - /// </summary> - [Route("/Plugins/{Id}", "DELETE", Summary = "Uninstalls a plugin")] - [Authenticated(Roles = "Admin")] - public class UninstallPlugin : IReturnVoid - { - /// <summary> - /// Gets or sets the id. - /// </summary> - /// <value>The id.</value> - [ApiMember(Name = "Id", Description = "Plugin Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Id { get; set; } - } - - /// <summary> - /// Class GetPluginConfiguration - /// </summary> - [Route("/Plugins/{Id}/Configuration", "GET", Summary = "Gets a plugin's configuration")] - [Authenticated] - public class GetPluginConfiguration - { - /// <summary> - /// Gets or sets the id. - /// </summary> - /// <value>The id.</value> - [ApiMember(Name = "Id", Description = "Plugin Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Id { get; set; } - } - - /// <summary> - /// Class UpdatePluginConfiguration - /// </summary> - [Route("/Plugins/{Id}/Configuration", "POST", Summary = "Updates a plugin's configuration")] - [Authenticated] - public class UpdatePluginConfiguration : IRequiresRequestStream, IReturnVoid - { - /// <summary> - /// Gets or sets the id. - /// </summary> - /// <value>The id.</value> - [ApiMember(Name = "Id", Description = "Plugin Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string Id { get; set; } - - /// <summary> - /// The raw Http Request Input Stream - /// </summary> - /// <value>The request stream.</value> - public Stream RequestStream { get; set; } - } - - //TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins, - // delete all these registration endpoints. They are only kept for compatibility. - [Route("/Registrations/{Name}", "GET", Summary = "Gets registration status for a feature", IsHidden = true)] - [Authenticated] - public class GetRegistration : IReturn<RegistrationInfo> - { - [ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Name { get; set; } - } - - /// <summary> - /// Class GetPluginSecurityInfo - /// </summary> - [Route("/Plugins/SecurityInfo", "GET", Summary = "Gets plugin registration information", IsHidden = true)] - [Authenticated] - public class GetPluginSecurityInfo : IReturn<PluginSecurityInfo> - { - } - - /// <summary> - /// Class UpdatePluginSecurityInfo - /// </summary> - [Route("/Plugins/SecurityInfo", "POST", Summary = "Updates plugin registration information", IsHidden = true)] - [Authenticated(Roles = "Admin")] - public class UpdatePluginSecurityInfo : PluginSecurityInfo, IReturnVoid - { - } - - [Route("/Plugins/RegistrationRecords/{Name}", "GET", Summary = "Gets registration status for a feature", IsHidden = true)] - [Authenticated] - public class GetRegistrationStatus - { - [ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Name { get; set; } - } - - // TODO these two classes are only kept for compability with paid plugins and should be removed - public class RegistrationInfo - { - public string Name { get; set; } - public DateTime ExpirationDate { get; set; } - public bool IsTrial { get; set; } - public bool IsRegistered { get; set; } - } - - public class MBRegistrationRecord - { - public DateTime ExpirationDate { get; set; } - public bool IsRegistered { get; set; } - public bool RegChecked { get; set; } - public bool RegError { get; set; } - public bool TrialVersion { get; set; } - public bool IsValid { get; set; } - } - - public class PluginSecurityInfo - { - public string SupporterKey { get; set; } - public bool IsMBSupporter { get; set; } - } - /// <summary> - /// Class PluginsService - /// </summary> - public class PluginService : BaseApiService - { - /// <summary> - /// The _json serializer - /// </summary> - private readonly IJsonSerializer _jsonSerializer; - - /// <summary> - /// The _app host - /// </summary> - private readonly IApplicationHost _appHost; - private readonly IInstallationManager _installationManager; - - public PluginService( - ILogger<PluginService> logger, - IServerConfigurationManager serverConfigurationManager, - IHttpResultFactory httpResultFactory, - IJsonSerializer jsonSerializer, - IApplicationHost appHost, - IInstallationManager installationManager) - : base(logger, serverConfigurationManager, httpResultFactory) - { - _appHost = appHost; - _installationManager = installationManager; - _jsonSerializer = jsonSerializer; - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetRegistrationStatus request) - { - var record = new MBRegistrationRecord - { - IsRegistered = true, - RegChecked = true, - TrialVersion = false, - IsValid = true, - RegError = false - }; - - return ToOptimizedResult(record); - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetPlugins request) - { - var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToArray(); - return ToOptimizedResult(result); - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetPluginConfiguration request) - { - var guid = new Guid(request.Id); - var plugin = _appHost.Plugins.First(p => p.Id == guid) as IHasPluginConfiguration; - - return ToOptimizedResult(plugin.Configuration); - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetPluginSecurityInfo request) - { - var result = new PluginSecurityInfo - { - IsMBSupporter = true, - SupporterKey = "IAmTotallyLegit" - }; - - return ToOptimizedResult(result); - } - - /// <summary> - /// Posts the specified request. - /// </summary> - /// <param name="request">The request.</param> - public Task Post(UpdatePluginSecurityInfo request) - { - return Task.CompletedTask; - } - - /// <summary> - /// Posts the specified request. - /// </summary> - /// <param name="request">The request.</param> - public async Task Post(UpdatePluginConfiguration request) - { - // We need to parse this manually because we told service stack not to with IRequiresRequestStream - // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs - var id = Guid.Parse(GetPathValue(1)); - - if (!(_appHost.Plugins.First(p => p.Id == id) is IHasPluginConfiguration plugin)) - { - throw new FileNotFoundException(); - } - - var configuration = (await _jsonSerializer.DeserializeFromStreamAsync(request.RequestStream, plugin.ConfigurationType).ConfigureAwait(false)) as BasePluginConfiguration; - - plugin.UpdateConfiguration(configuration); - } - - /// <summary> - /// Deletes the specified request. - /// </summary> - /// <param name="request">The request.</param> - public void Delete(UninstallPlugin request) - { - var guid = new Guid(request.Id); - var plugin = _appHost.Plugins.First(p => p.Id == guid); - - _installationManager.UninstallPlugin(plugin); - } - } -} |
