ASC.Web.Core: WebPluginManager: read system plugins from storage
This commit is contained in:
parent
166b5ddeee
commit
6af5cf8295
@ -91,14 +91,14 @@ static file class Queries
|
||||
(WebPluginDbContext ctx, int tenantId) =>
|
||||
ctx.WebPlugins
|
||||
.AsNoTracking()
|
||||
.Where(r => r.TenantId == Tenant.DefaultTenant || r.TenantId == tenantId));
|
||||
.Where(r => r.TenantId == tenantId));
|
||||
|
||||
public static readonly Func<WebPluginDbContext, int, int, Task<DbWebPlugin>>
|
||||
WebPluginByIdAsync = EF.CompileAsyncQuery(
|
||||
(WebPluginDbContext ctx, int tenantId, int id) =>
|
||||
ctx.WebPlugins
|
||||
.AsNoTracking()
|
||||
.Where(r => r.TenantId == Tenant.DefaultTenant || r.TenantId == tenantId)
|
||||
.Where(r => r.TenantId == tenantId)
|
||||
.Where(r => r.Id == id)
|
||||
.FirstOrDefault());
|
||||
|
||||
|
@ -414,8 +414,7 @@
|
||||
"extension": ".zip",
|
||||
"maxSize": 5242880,
|
||||
"allow": ["upload", "delete"],
|
||||
"assetExtensions": [".jpg", ".jpeg", ".png", ".svg"],
|
||||
"systemUrl": "https://d1abtk7kda2my2.cloudfront.net/v9.5.0/webplugins/system.json"
|
||||
"assetExtensions": [".jpg", ".jpeg", ".png", ".svg"]
|
||||
},
|
||||
"aws": {
|
||||
"cloudWatch": {
|
||||
|
@ -81,13 +81,13 @@ public class WebPluginsController : BaseSettingsController
|
||||
[HttpGet("webplugins")]
|
||||
public async Task<IEnumerable<WebPluginDto>> GetWebPluginsAsync(bool? enabled = null)
|
||||
{
|
||||
var outDto = await _webPluginManager.GetSystemWebPluginsAsync<WebPluginDto>();
|
||||
var plugins = new List<DbWebPlugin>();
|
||||
|
||||
var dbPlugins = await _webPluginManager.GetWebPluginsAsync(Tenant.Id);
|
||||
plugins.AddRange(await _webPluginManager.GetSystemWebPluginsAsync());
|
||||
|
||||
var dtoPlugins = _mapper.Map<List<DbWebPlugin>, List<WebPluginDto>>(dbPlugins);
|
||||
plugins.AddRange(await _webPluginManager.GetWebPluginsAsync(Tenant.Id));
|
||||
|
||||
outDto.AddRange(dtoPlugins);
|
||||
var outDto = _mapper.Map<List<DbWebPlugin>, List<WebPluginDto>>(plugins);
|
||||
|
||||
if (enabled.HasValue)
|
||||
{
|
||||
@ -101,11 +101,6 @@ public class WebPluginsController : BaseSettingsController
|
||||
|
||||
foreach (var dto in outDto)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(dto.Url))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dto.System && systemUrlTemplate == null)
|
||||
{
|
||||
systemUrlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(Tenant.DefaultTenant);
|
||||
@ -130,9 +125,9 @@ public class WebPluginsController : BaseSettingsController
|
||||
|
||||
var outDto = _mapper.Map<DbWebPlugin, WebPluginDto>(plugin);
|
||||
|
||||
if (outDto != null && string.IsNullOrEmpty(outDto.Url))
|
||||
if (outDto != null)
|
||||
{
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(outDto.System ? Tenant.DefaultTenant : Tenant.Id);
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(Tenant.Id);
|
||||
|
||||
outDto.Url = string.Format(urlTemplate, outDto.Name);
|
||||
}
|
||||
@ -155,4 +150,39 @@ public class WebPluginsController : BaseSettingsController
|
||||
|
||||
await _webPluginManager.DeleteWebPluginAsync(Tenant.Id, id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet("webplugins/system/{name}")]
|
||||
public async Task<WebPluginDto> GetSystemWebPluginByNameAsync(string name)
|
||||
{
|
||||
var plugin = await _webPluginManager.GetSystemWebPluginAsync(name);
|
||||
|
||||
var outDto = _mapper.Map<DbWebPlugin, WebPluginDto>(plugin);
|
||||
|
||||
if (outDto != null)
|
||||
{
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(Tenant.DefaultTenant);
|
||||
|
||||
outDto.Url = string.Format(urlTemplate, outDto.Name);
|
||||
}
|
||||
|
||||
return outDto;
|
||||
}
|
||||
|
||||
[HttpPut("webplugins/system/{name}")]
|
||||
public async Task UpdateSystemWebPluginAsync(string name, WebPluginRequestsDto inDto)
|
||||
{
|
||||
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
|
||||
|
||||
await _webPluginManager.UpdateSystemWebPluginAsync(name, inDto.Enabled);
|
||||
}
|
||||
|
||||
[HttpDelete("webplugins/system/{name}")]
|
||||
public async Task DeleteSystemWebPluginAsync(string name)
|
||||
{
|
||||
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
|
||||
|
||||
await _webPluginManager.DeleteSystemWebPluginAsync(name);
|
||||
}
|
||||
}
|
||||
|
@ -41,9 +41,9 @@ public class WebPluginCache
|
||||
_notify.Subscribe((i) => _сache.Remove(i.Key), CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
public T Get<T>(string key) where T : class
|
||||
public List<DbWebPlugin> Get(string key)
|
||||
{
|
||||
return _сache.Get<T>(key);
|
||||
return _сache.Get<List<DbWebPlugin>>(key);
|
||||
}
|
||||
|
||||
public void Insert(string key, object value)
|
||||
@ -71,7 +71,7 @@ public class WebPluginManager
|
||||
private const string AssetsFolderName = "assets";
|
||||
|
||||
private readonly CoreBaseSettings _coreBaseSettings;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
private readonly SettingsManager _settingsManager;
|
||||
private readonly DbWebPluginService _webPluginService;
|
||||
private readonly WebPluginSettings _webPluginSettings;
|
||||
private readonly WebPluginCache _webPluginCache;
|
||||
@ -81,7 +81,7 @@ public class WebPluginManager
|
||||
|
||||
public WebPluginManager(
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
IHttpClientFactory clientFactory,
|
||||
SettingsManager settingsManager,
|
||||
DbWebPluginService webPluginService,
|
||||
WebPluginSettings webPluginSettings,
|
||||
WebPluginCache webPluginCache,
|
||||
@ -90,7 +90,7 @@ public class WebPluginManager
|
||||
ILogger<WebPluginManager> log)
|
||||
{
|
||||
_coreBaseSettings = coreBaseSettings;
|
||||
_clientFactory = clientFactory;
|
||||
_settingsManager = settingsManager;
|
||||
_webPluginService = webPluginService;
|
||||
_webPluginSettings = webPluginSettings;
|
||||
_webPluginCache = webPluginCache;
|
||||
@ -114,7 +114,9 @@ public class WebPluginManager
|
||||
|
||||
private async Task<IDataStore> GetPluginStorageAsync(int tenantId)
|
||||
{
|
||||
var storage = await _storageFactory.GetStorageAsync(tenantId, tenantId == Tenant.DefaultTenant ? StorageSystemModuleName : StorageModuleName);
|
||||
var module = tenantId == Tenant.DefaultTenant ? StorageSystemModuleName : StorageModuleName;
|
||||
|
||||
var storage = await _storageFactory.GetStorageAsync(tenantId, module);
|
||||
|
||||
return storage;
|
||||
}
|
||||
@ -124,11 +126,6 @@ public class WebPluginManager
|
||||
return $"{StorageModuleName}:{tenantId}";
|
||||
}
|
||||
|
||||
private static string GetSystemCacheKey()
|
||||
{
|
||||
return StorageSystemModuleName;
|
||||
}
|
||||
|
||||
public async Task<string> GetPluginUrlTemplateAsync(int tenantId)
|
||||
{
|
||||
var storage = await GetPluginStorageAsync(tenantId);
|
||||
@ -140,15 +137,45 @@ public class WebPluginManager
|
||||
|
||||
public async Task<DbWebPlugin> AddWebPluginFromFileAsync(int tenantId, IFormFile file)
|
||||
{
|
||||
var system = tenantId == Tenant.DefaultTenant;
|
||||
|
||||
DemandWebPlugins("upload");
|
||||
|
||||
var system = tenantId == Tenant.DefaultTenant;
|
||||
|
||||
if (system && !_coreBaseSettings.Standalone)
|
||||
{
|
||||
throw new SecurityException("System plugin");
|
||||
}
|
||||
|
||||
var webPlugin = await SaveWebPluginToStorageAsync(tenantId, file);
|
||||
|
||||
webPlugin.TenantId = tenantId;
|
||||
webPlugin.Enabled = true;
|
||||
webPlugin.System = system;
|
||||
|
||||
if (!system)
|
||||
{
|
||||
var existingPlugin = await _webPluginService.GetByNameAsync(tenantId, webPlugin.Name);
|
||||
|
||||
if (existingPlugin != null)
|
||||
{
|
||||
webPlugin.Id = existingPlugin.Id;
|
||||
}
|
||||
|
||||
webPlugin.CreateBy = _authContext.CurrentAccount.ID;
|
||||
webPlugin.CreateOn = DateTime.UtcNow;
|
||||
|
||||
webPlugin = await _webPluginService.SaveAsync(webPlugin);
|
||||
}
|
||||
|
||||
var key = GetCacheKey(tenantId);
|
||||
|
||||
_webPluginCache.Remove(key);
|
||||
|
||||
return webPlugin;
|
||||
}
|
||||
|
||||
private async Task<DbWebPlugin> SaveWebPluginToStorageAsync(int tenantId, IFormFile file)
|
||||
{
|
||||
if (Path.GetExtension(file.FileName)?.ToLowerInvariant() != _webPluginSettings.Extension)
|
||||
{
|
||||
throw new ArgumentException("Wrong file extension");
|
||||
@ -198,26 +225,12 @@ public class WebPluginManager
|
||||
throw new ArgumentException("Wrong plugin name");
|
||||
}
|
||||
|
||||
var existingPlugin = await _webPluginService.GetByNameAsync(tenantId, webPlugin.Name);
|
||||
if (existingPlugin != null)
|
||||
if (await storage.IsDirectoryAsync(webPlugin.Name))
|
||||
{
|
||||
if (webPlugin.Version == existingPlugin.Version)
|
||||
{
|
||||
throw new ArgumentException("Plugin already exist");
|
||||
}
|
||||
|
||||
webPlugin.Id = existingPlugin.Id;
|
||||
|
||||
await storage.DeleteDirectoryAsync(string.Empty, webPlugin.Name);
|
||||
await storage.DeleteDirectoryAsync(webPlugin.Name);
|
||||
}
|
||||
|
||||
webPlugin.TenantId = tenantId;
|
||||
webPlugin.CreateBy = _authContext.CurrentAccount.ID;
|
||||
webPlugin.CreateOn = DateTime.UtcNow;
|
||||
webPlugin.Enabled = true;
|
||||
webPlugin.System = system;
|
||||
|
||||
webPlugin = await _webPluginService.SaveAsync(webPlugin);
|
||||
uri = await storage.SaveAsync(Path.Combine(webPlugin.Name, ConfigFileName), stream);
|
||||
}
|
||||
|
||||
using (var stream = zipFile.GetInputStream(pluginFile))
|
||||
@ -244,10 +257,6 @@ public class WebPluginManager
|
||||
}
|
||||
}
|
||||
|
||||
var key = GetCacheKey(tenantId);
|
||||
|
||||
_webPluginCache.Remove(key);
|
||||
|
||||
return webPlugin;
|
||||
}
|
||||
|
||||
@ -257,11 +266,11 @@ public class WebPluginManager
|
||||
|
||||
var key = GetCacheKey(tenantId);
|
||||
|
||||
var plugins = _webPluginCache.Get<List<DbWebPlugin>>(key);
|
||||
var plugins = _webPluginCache.Get(key);
|
||||
|
||||
if (plugins == null)
|
||||
{
|
||||
plugins = await _webPluginService.GetAsync(tenantId) ?? new List<DbWebPlugin>();
|
||||
plugins = await _webPluginService.GetAsync(tenantId);
|
||||
|
||||
_webPluginCache.Insert(key, plugins);
|
||||
}
|
||||
@ -284,11 +293,6 @@ public class WebPluginManager
|
||||
|
||||
var plugin = await _webPluginService.GetByIdAsync(tenantId, id) ?? throw new ItemNotFoundException("Plugin not found");
|
||||
|
||||
if (plugin.System && !_coreBaseSettings.Standalone)
|
||||
{
|
||||
throw new SecurityException("System plugin");
|
||||
}
|
||||
|
||||
await _webPluginService.UpdateAsync(tenantId, plugin.Id, enabled);
|
||||
|
||||
var key = GetCacheKey(tenantId);
|
||||
@ -302,16 +306,11 @@ public class WebPluginManager
|
||||
|
||||
var plugin = await _webPluginService.GetByIdAsync(tenantId, id) ?? throw new ItemNotFoundException("Plugin not found");
|
||||
|
||||
if (plugin.System && !_coreBaseSettings.Standalone)
|
||||
{
|
||||
throw new SecurityException("System plugin");
|
||||
}
|
||||
|
||||
await _webPluginService.DeleteAsync(tenantId, plugin.Id);
|
||||
|
||||
var storage = await GetPluginStorageAsync(tenantId);
|
||||
|
||||
await storage.DeleteDirectoryAsync(string.Empty, plugin.Name);
|
||||
await storage.DeleteDirectoryAsync(plugin.Name);
|
||||
|
||||
var key = GetCacheKey(tenantId);
|
||||
|
||||
@ -319,15 +318,16 @@ public class WebPluginManager
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<T>> GetSystemWebPluginsAsync<T>()
|
||||
{
|
||||
var key = GetSystemCacheKey();
|
||||
|
||||
var systemPlugins = _webPluginCache.Get<List<T>>(key);
|
||||
public async Task<List<DbWebPlugin>> GetSystemWebPluginsAsync()
|
||||
{
|
||||
var key = GetCacheKey(Tenant.DefaultTenant);
|
||||
|
||||
var systemPlugins = _webPluginCache.Get(key);
|
||||
|
||||
if (systemPlugins == null)
|
||||
{
|
||||
systemPlugins = await GetSystemWebPluginsFromUrlAsync<T>() ?? new List<T>();
|
||||
systemPlugins = await GetSystemWebPluginsFromStorageAsync();
|
||||
|
||||
_webPluginCache.Insert(key, systemPlugins);
|
||||
}
|
||||
@ -335,36 +335,129 @@ public class WebPluginManager
|
||||
return systemPlugins;
|
||||
}
|
||||
|
||||
private async Task<List<T>> GetSystemWebPluginsFromUrlAsync<T>()
|
||||
private async Task<List<DbWebPlugin>> GetSystemWebPluginsFromStorageAsync()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_webPluginSettings.SystemUrl))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var systemPlugins = new List<DbWebPlugin>();
|
||||
|
||||
try
|
||||
var systemWebPluginSettings = await _settingsManager.LoadForDefaultTenantAsync<SystemWebPluginSettings>();
|
||||
|
||||
var disabledPlugins = systemWebPluginSettings?.DisabledPlugins ?? new List<string>();
|
||||
|
||||
var storage = await GetPluginStorageAsync(Tenant.DefaultTenant);
|
||||
|
||||
var configFiles = await storage.ListFilesRelativeAsync(string.Empty, string.Empty, ConfigFileName, true).ToArrayAsync();
|
||||
|
||||
foreach (var path in configFiles)
|
||||
{
|
||||
var request = new HttpRequestMessage
|
||||
try
|
||||
{
|
||||
RequestUri = new Uri(_webPluginSettings.SystemUrl)
|
||||
};
|
||||
using var readStream = await storage.GetReadStreamAsync(path);
|
||||
|
||||
var httpClient = _clientFactory.CreateClient();
|
||||
using var reader = new StreamReader(readStream);
|
||||
|
||||
using var response = await httpClient.SendAsync(request);
|
||||
using var responseStream = await response.Content.ReadAsStreamAsync();
|
||||
using var reader = new StreamReader(responseStream);
|
||||
var configContent = reader.ReadToEnd();
|
||||
|
||||
var json = await reader.ReadToEndAsync();
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
var systemPlugins = JsonConvert.DeserializeObject<List<T>>(json);
|
||||
var webPlugin = System.Text.Json.JsonSerializer.Deserialize<DbWebPlugin>(configContent, options);
|
||||
|
||||
return systemPlugins;
|
||||
webPlugin.TenantId = Tenant.DefaultTenant;
|
||||
webPlugin.System = true;
|
||||
webPlugin.Enabled = !disabledPlugins.Contains(webPlugin.Name);
|
||||
|
||||
systemPlugins.Add(webPlugin);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.ErrorWithException(e);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
return systemPlugins;
|
||||
}
|
||||
|
||||
public async Task<DbWebPlugin> GetSystemWebPluginAsync(string name)
|
||||
{
|
||||
var systemWebPluginSettings = await _settingsManager.LoadForDefaultTenantAsync<SystemWebPluginSettings>();
|
||||
|
||||
var disabledPlugins = systemWebPluginSettings?.DisabledPlugins ?? new List<string>();
|
||||
|
||||
var storage = await GetPluginStorageAsync(Tenant.DefaultTenant);
|
||||
|
||||
var path = Path.Combine(name, ConfigFileName);
|
||||
|
||||
if (!await storage.IsFileAsync(path))
|
||||
{
|
||||
_log.ErrorWithException(e);
|
||||
return null;
|
||||
throw new ItemNotFoundException("Plugin not found");
|
||||
}
|
||||
|
||||
using var readStream = await storage.GetReadStreamAsync(path);
|
||||
|
||||
using var reader = new StreamReader(readStream);
|
||||
|
||||
var configContent = reader.ReadToEnd();
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
var webPlugin = System.Text.Json.JsonSerializer.Deserialize<DbWebPlugin>(configContent, options);
|
||||
|
||||
webPlugin.TenantId = Tenant.DefaultTenant;
|
||||
webPlugin.System = true;
|
||||
webPlugin.Enabled = !disabledPlugins.Contains(webPlugin.Name);
|
||||
|
||||
return webPlugin;
|
||||
}
|
||||
|
||||
public async Task UpdateSystemWebPluginAsync(string name, bool enabled)
|
||||
{
|
||||
DemandWebPlugins();
|
||||
|
||||
var systemWebPluginSettings = await _settingsManager.LoadForDefaultTenantAsync<SystemWebPluginSettings>();
|
||||
|
||||
var disabledPlugins = systemWebPluginSettings?.DisabledPlugins ?? new List<string>();
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
disabledPlugins.Remove(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
disabledPlugins.Add(name);
|
||||
}
|
||||
|
||||
systemWebPluginSettings.DisabledPlugins = disabledPlugins.Any() ? disabledPlugins : null;
|
||||
|
||||
await _settingsManager.SaveForDefaultTenantAsync(systemWebPluginSettings);
|
||||
|
||||
var key = GetCacheKey(Tenant.DefaultTenant);
|
||||
|
||||
_webPluginCache.Remove(key);
|
||||
}
|
||||
|
||||
public async Task DeleteSystemWebPluginAsync(string name)
|
||||
{
|
||||
DemandWebPlugins("delete");
|
||||
|
||||
if (!_coreBaseSettings.Standalone)
|
||||
{
|
||||
throw new SecurityException("System plugin");
|
||||
}
|
||||
|
||||
var storage = await GetPluginStorageAsync(Tenant.DefaultTenant);
|
||||
|
||||
if (!await storage.IsDirectoryAsync(name))
|
||||
{
|
||||
throw new ItemNotFoundException("Plugin not found");
|
||||
}
|
||||
|
||||
await UpdateSystemWebPluginAsync(name, true);
|
||||
|
||||
await storage.DeleteDirectoryAsync(name);
|
||||
}
|
||||
}
|
||||
|
@ -69,10 +69,20 @@ public class WebPluginSettings
|
||||
get => _assetExtensions ?? Array.Empty<string>();
|
||||
set => _assetExtensions = value;
|
||||
}
|
||||
|
||||
public string SystemUrl
|
||||
{
|
||||
get => _systemUrl;
|
||||
set => _systemUrl = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class SystemWebPluginSettings : ISettings<SystemWebPluginSettings>
|
||||
{
|
||||
public List<string> DisabledPlugins { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid ID
|
||||
{
|
||||
get { return new Guid("{33039FD8-CF74-46B5-9AF2-2B3D4B651F31}"); }
|
||||
}
|
||||
|
||||
public SystemWebPluginSettings GetDefault()
|
||||
{
|
||||
return new SystemWebPluginSettings();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user