Merge branch 'feature/web-plugins' of github.com:ONLYOFFICE/DocSpace into feature/web-plugins
This commit is contained in:
commit
aa26f284fa
@ -62,13 +62,11 @@ public class DbWebPluginService
|
||||
return await Queries.WebPluginByNameAsync(dbContext, tenantId, name);
|
||||
}
|
||||
|
||||
public async Task<List<DbWebPlugin>> GetAsync(int tenantId, bool? enabled = null)
|
||||
public async Task<List<DbWebPlugin>> GetAsync(int tenantId)
|
||||
{
|
||||
await using var dbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
return enabled.HasValue
|
||||
? await Queries.WebPluginsByStatusAsync(dbContext, tenantId, enabled.Value).ToListAsync()
|
||||
: await Queries.WebPluginsAsync(dbContext, tenantId).ToListAsync();
|
||||
return await Queries.WebPluginsAsync(dbContext, tenantId).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(int tenantId, int id, bool enabled)
|
||||
@ -95,14 +93,6 @@ static file class Queries
|
||||
.AsNoTracking()
|
||||
.Where(r => r.TenantId == tenantId));
|
||||
|
||||
public static readonly Func<WebPluginDbContext, int, bool, IAsyncEnumerable<DbWebPlugin>>
|
||||
WebPluginsByStatusAsync = EF.CompileAsyncQuery(
|
||||
(WebPluginDbContext ctx, int tenantId, bool enabled) =>
|
||||
ctx.WebPlugins
|
||||
.AsNoTracking()
|
||||
.Where(r => r.TenantId == tenantId)
|
||||
.Where(r => r.Enabled == enabled));
|
||||
|
||||
public static readonly Func<WebPluginDbContext, int, int, Task<DbWebPlugin>>
|
||||
WebPluginByIdAsync = EF.CompileAsyncQuery(
|
||||
(WebPluginDbContext ctx, int tenantId, int id) =>
|
||||
|
@ -451,8 +451,9 @@
|
||||
"plugins": {
|
||||
"enabled": "true",
|
||||
"extension": ".zip",
|
||||
"max-size": 5242880,
|
||||
"allow": ["upload", "delete"]
|
||||
"maxSize": 5242880,
|
||||
"allow": ["upload", "delete"],
|
||||
"assetExtensions": [".jpg", ".jpeg", ".png", ".svg"]
|
||||
},
|
||||
"aws": {
|
||||
"cloudWatch": {
|
||||
|
@ -134,6 +134,16 @@
|
||||
"type": "disc",
|
||||
"path": "$STORAGE_ROOT\\Studio\\{0}\\webplugins",
|
||||
"virtualpath": "~/studio/{0}/webplugins"
|
||||
},
|
||||
{
|
||||
"name": "systemwebplugins",
|
||||
"data": "00000000-0000-0000-0000-000000000000",
|
||||
"type": "disc",
|
||||
"path": "$STORAGE_ROOT\\Studio\\webplugins",
|
||||
"virtualpath": "~/studio/webplugins",
|
||||
"appendTenantId": false,
|
||||
"disableMigrate": true,
|
||||
"disableEncryption": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ class PluginStore {
|
||||
...this.pluginFrame.contentWindow.Plugins[plugin.pluginName],
|
||||
});
|
||||
|
||||
newPlugin.createBy = newPlugin.createBy.displayName;
|
||||
// newPlugin.createBy = newPlugin.createBy.displayName;
|
||||
newPlugin.scopes = newPlugin.scopes.split(",");
|
||||
newPlugin.iconUrl = getPluginUrl(newPlugin.url, "");
|
||||
|
||||
@ -226,7 +226,7 @@ class PluginStore {
|
||||
if (!plugin || !plugin.enabled) return;
|
||||
|
||||
if (plugin.scopes.includes(PluginScopes.API)) {
|
||||
plugin.setAPI(origin, proxy, prefix);
|
||||
plugin.setAPI && plugin.setAPI(origin, proxy, prefix);
|
||||
}
|
||||
|
||||
if (plugin.onLoadCallback) {
|
||||
|
@ -49,8 +49,10 @@ public class WebPluginsController : BaseSettingsController
|
||||
}
|
||||
|
||||
[HttpPost("webplugins")]
|
||||
public async Task<WebPluginDto> AddWebPluginFromFile()
|
||||
public async Task<WebPluginDto> AddWebPluginFromFile(bool system)
|
||||
{
|
||||
var tenantId = system ? Tenant.DefaultTenant : Tenant.Id;
|
||||
|
||||
await _permissionContext.DemandPermissionsAsync(SecutiryConstants.EditPortalSettings);
|
||||
|
||||
if (HttpContext.Request.Form?.Files == null || HttpContext.Request.Form.Files.Count == 0)
|
||||
@ -65,11 +67,11 @@ public class WebPluginsController : BaseSettingsController
|
||||
|
||||
var file = HttpContext.Request.Form.Files[0] ?? throw new ArgumentException("Input file is null");
|
||||
|
||||
var plugin = await _webPluginManager.AddWebPluginFromFile(Tenant.Id, file);
|
||||
var plugin = await _webPluginManager.AddWebPluginFromFileAsync(tenantId, file);
|
||||
|
||||
var outDto = _mapper.Map<DbWebPlugin, WebPluginDto>(plugin);
|
||||
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplate(Tenant.Id);
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(tenantId);
|
||||
|
||||
outDto.Url = string.Format(urlTemplate, outDto.Name);
|
||||
|
||||
@ -79,17 +81,37 @@ public class WebPluginsController : BaseSettingsController
|
||||
[HttpGet("webplugins")]
|
||||
public async Task<IEnumerable<WebPluginDto>> GetWebPluginsAsync(bool? enabled = null)
|
||||
{
|
||||
var plugins = await _webPluginManager.GetWebPluginsAsync(Tenant.Id, enabled);
|
||||
var plugins = new List<DbWebPlugin>();
|
||||
|
||||
var outDto = _mapper.Map<IEnumerable<DbWebPlugin>, IEnumerable<WebPluginDto>>(plugins);
|
||||
plugins.AddRange(await _webPluginManager.GetSystemWebPluginsAsync());
|
||||
|
||||
if (outDto != null && outDto.Any())
|
||||
plugins.AddRange(await _webPluginManager.GetWebPluginsAsync(Tenant.Id));
|
||||
|
||||
var outDto = _mapper.Map<List<DbWebPlugin>, List<WebPluginDto>>(plugins);
|
||||
|
||||
if (enabled.HasValue)
|
||||
{
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplate(Tenant.Id);
|
||||
outDto = outDto.Where(i => i.Enabled == enabled).ToList();
|
||||
}
|
||||
|
||||
if (outDto.Any())
|
||||
{
|
||||
string urlTemplate = null;
|
||||
string systemUrlTemplate = null;
|
||||
|
||||
foreach (var dto in outDto)
|
||||
{
|
||||
dto.Url = string.Format(urlTemplate, dto.Name);
|
||||
if (dto.System && systemUrlTemplate == null)
|
||||
{
|
||||
systemUrlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(Tenant.DefaultTenant);
|
||||
}
|
||||
|
||||
if (!dto.System && urlTemplate == null)
|
||||
{
|
||||
urlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(Tenant.Id);
|
||||
}
|
||||
|
||||
dto.Url = string.Format(dto.System ? systemUrlTemplate : urlTemplate, dto.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +127,7 @@ public class WebPluginsController : BaseSettingsController
|
||||
|
||||
if (outDto != null)
|
||||
{
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplate(Tenant.Id);
|
||||
var urlTemplate = await _webPluginManager.GetPluginUrlTemplateAsync(Tenant.Id);
|
||||
|
||||
outDto.Url = string.Format(urlTemplate, outDto.Name);
|
||||
}
|
||||
@ -128,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);
|
||||
}
|
||||
}
|
||||
|
@ -416,6 +416,7 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="protos\web_plugin_cache_item.proto" />
|
||||
<Protobuf Include="protos\sms_key_cache_key.proto" />
|
||||
<Protobuf Include="protos\tenant_logo_cache_item.proto" />
|
||||
<Protobuf Include="protos\mail_service_helper_cache.proto" />
|
||||
|
@ -26,29 +26,77 @@
|
||||
|
||||
namespace ASC.Web.Core;
|
||||
|
||||
[Singletone]
|
||||
public class WebPluginCache
|
||||
{
|
||||
private readonly ICache _сache;
|
||||
private readonly ICacheNotify<WebPluginCacheItem> _notify;
|
||||
private readonly TimeSpan _cacheExpiration = TimeSpan.FromDays(1);
|
||||
|
||||
public WebPluginCache(ICacheNotify<WebPluginCacheItem> notify, ICache cache)
|
||||
{
|
||||
_сache = cache;
|
||||
_notify = notify;
|
||||
|
||||
_notify.Subscribe((i) => _сache.Remove(i.Key), CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
public List<DbWebPlugin> Get(string key)
|
||||
{
|
||||
return _сache.Get<List<DbWebPlugin>>(key);
|
||||
}
|
||||
|
||||
public void Insert(string key, object value)
|
||||
{
|
||||
_notify.Publish(new WebPluginCacheItem { Key = key }, CacheNotifyAction.Remove);
|
||||
|
||||
_сache.Insert(key, value, _cacheExpiration);
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
_notify.Publish(new WebPluginCacheItem { Key = key }, CacheNotifyAction.Remove);
|
||||
|
||||
_сache.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class WebPluginManager
|
||||
{
|
||||
private const string StorageSystemModuleName = "systemwebplugins";
|
||||
private const string StorageModuleName = "webplugins";
|
||||
private const string ConfigFileName = "config.json";
|
||||
private const string PluginFileName = "plugin.js";
|
||||
private const string AssetsFolderName = "assets";
|
||||
|
||||
private readonly CoreBaseSettings _coreBaseSettings;
|
||||
private readonly SettingsManager _settingsManager;
|
||||
private readonly DbWebPluginService _webPluginService;
|
||||
private readonly WebPluginSettings _webPluginSettings;
|
||||
private readonly WebPluginCache _webPluginCache;
|
||||
private readonly StorageFactory _storageFactory;
|
||||
private readonly AuthContext _authContext;
|
||||
private readonly ILogger<WebPluginManager> _log;
|
||||
|
||||
public WebPluginManager(
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
SettingsManager settingsManager,
|
||||
DbWebPluginService webPluginService,
|
||||
WebPluginSettings webPluginSettings,
|
||||
WebPluginCache webPluginCache,
|
||||
StorageFactory storageFactory,
|
||||
AuthContext authContext)
|
||||
AuthContext authContext,
|
||||
ILogger<WebPluginManager> log)
|
||||
{
|
||||
_coreBaseSettings = coreBaseSettings;
|
||||
_settingsManager = settingsManager;
|
||||
_webPluginService = webPluginService;
|
||||
_webPluginSettings = webPluginSettings;
|
||||
_webPluginCache = webPluginCache;
|
||||
_storageFactory = storageFactory;
|
||||
_authContext = authContext;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
private void DemandWebPlugins(string action = null)
|
||||
@ -58,25 +106,76 @@ public class WebPluginManager
|
||||
throw new SecurityException("Plugins disabled");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(action) && !_webPluginSettings.Allow.Contains(action))
|
||||
if (!string.IsNullOrWhiteSpace(action) && _webPluginSettings.Allow.Any() && !_webPluginSettings.Allow.Contains(action))
|
||||
{
|
||||
throw new SecurityException("Forbidden action");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> GetPluginUrlTemplate(int tenantId)
|
||||
private async Task<IDataStore> GetPluginStorageAsync(int tenantId)
|
||||
{
|
||||
var storage = await _storageFactory.GetStorageAsync(tenantId, StorageModuleName);
|
||||
var module = tenantId == Tenant.DefaultTenant ? StorageSystemModuleName : StorageModuleName;
|
||||
|
||||
var storage = await _storageFactory.GetStorageAsync(tenantId, module);
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
private static string GetCacheKey(int tenantId)
|
||||
{
|
||||
return $"{StorageModuleName}:{tenantId}";
|
||||
}
|
||||
|
||||
public async Task<string> GetPluginUrlTemplateAsync(int tenantId)
|
||||
{
|
||||
var storage = await GetPluginStorageAsync(tenantId);
|
||||
|
||||
var uri = await storage.GetUriAsync(Path.Combine("{0}", PluginFileName));
|
||||
|
||||
return uri?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
public async Task<DbWebPlugin> AddWebPluginFromFile(int tenantId, IFormFile file)
|
||||
public async Task<DbWebPlugin> AddWebPluginFromFileAsync(int tenantId, IFormFile file)
|
||||
{
|
||||
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");
|
||||
@ -87,7 +186,7 @@ public class WebPluginManager
|
||||
throw new ArgumentException("File size exceeds limit");
|
||||
}
|
||||
|
||||
var storage = await _storageFactory.GetStorageAsync(tenantId, StorageModuleName);
|
||||
var storage = await GetPluginStorageAsync(tenantId);
|
||||
|
||||
DbWebPlugin webPlugin = null;
|
||||
Uri uri = null;
|
||||
@ -114,34 +213,24 @@ public class WebPluginManager
|
||||
|
||||
webPlugin = System.Text.Json.JsonSerializer.Deserialize<DbWebPlugin>(configContent, options);
|
||||
|
||||
if (webPlugin == null || string.IsNullOrEmpty(webPlugin.Name))
|
||||
if (webPlugin == null)
|
||||
{
|
||||
throw new ArgumentException("Wrong plugin archive");
|
||||
}
|
||||
|
||||
//TODO: think about special characters
|
||||
webPlugin.Name = webPlugin.Name.Replace(" ", string.Empty).ToLowerInvariant();
|
||||
var nameRegex = new Regex(@"^[a-z0-9_.-]+$");
|
||||
|
||||
var existingPlugin = await _webPluginService.GetByNameAsync(tenantId, webPlugin.Name);
|
||||
if (existingPlugin != null)
|
||||
if (string.IsNullOrEmpty(webPlugin.Name) || !nameRegex.IsMatch(webPlugin.Name) || webPlugin.Name.StartsWith('.'))
|
||||
{
|
||||
if (webPlugin.Version == existingPlugin.Version)
|
||||
{
|
||||
throw new ArgumentException("Plugin already exist");
|
||||
}
|
||||
|
||||
webPlugin.Id = existingPlugin.Id;
|
||||
|
||||
await storage.DeleteDirectoryAsync(string.Empty, webPlugin.Name);
|
||||
throw new ArgumentException("Wrong plugin name");
|
||||
}
|
||||
|
||||
webPlugin.TenantId = tenantId;
|
||||
webPlugin.CreateBy = _authContext.CurrentAccount.ID;
|
||||
webPlugin.CreateOn = DateTime.UtcNow;
|
||||
webPlugin.Enabled = true;
|
||||
webPlugin.System = false;
|
||||
if (await storage.IsDirectoryAsync(webPlugin.Name))
|
||||
{
|
||||
await storage.DeleteDirectoryAsync(webPlugin.Name);
|
||||
}
|
||||
|
||||
webPlugin = await _webPluginService.SaveAsync(webPlugin);
|
||||
uri = await storage.SaveAsync(Path.Combine(webPlugin.Name, ConfigFileName), stream);
|
||||
}
|
||||
|
||||
using (var stream = zipFile.GetInputStream(pluginFile))
|
||||
@ -153,6 +242,13 @@ public class WebPluginManager
|
||||
{
|
||||
if (zipEntry.IsFile && zipEntry.Name.StartsWith(AssetsFolderName))
|
||||
{
|
||||
var ext = Path.GetExtension(zipEntry.Name);
|
||||
|
||||
if (_webPluginSettings.AssetExtensions.Any() && !_webPluginSettings.AssetExtensions.Contains(ext))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using (var stream = zipFile.GetInputStream(zipEntry))
|
||||
{
|
||||
uri = await storage.SaveAsync(Path.Combine(webPlugin.Name, zipEntry.Name), stream);
|
||||
@ -164,11 +260,20 @@ public class WebPluginManager
|
||||
return webPlugin;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DbWebPlugin>> GetWebPluginsAsync(int tenantId, bool? enabled = null)
|
||||
public async Task<List<DbWebPlugin>> GetWebPluginsAsync(int tenantId)
|
||||
{
|
||||
DemandWebPlugins();
|
||||
|
||||
var plugins = await _webPluginService.GetAsync(tenantId, enabled);
|
||||
var key = GetCacheKey(tenantId);
|
||||
|
||||
var plugins = _webPluginCache.Get(key);
|
||||
|
||||
if (plugins == null)
|
||||
{
|
||||
plugins = await _webPluginService.GetAsync(tenantId);
|
||||
|
||||
_webPluginCache.Insert(key, plugins);
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
@ -188,12 +293,11 @@ public class WebPluginManager
|
||||
|
||||
var plugin = await _webPluginService.GetByIdAsync(tenantId, id) ?? throw new ItemNotFoundException("Plugin not found");
|
||||
|
||||
if (plugin.System)
|
||||
{
|
||||
throw new SecurityException("System plugin");
|
||||
}
|
||||
|
||||
await _webPluginService.UpdateAsync(tenantId, plugin.Id, enabled);
|
||||
|
||||
var key = GetCacheKey(tenantId);
|
||||
|
||||
_webPluginCache.Remove(key);
|
||||
}
|
||||
|
||||
public async Task DeleteWebPluginAsync(int tenantId, int id)
|
||||
@ -202,15 +306,158 @@ public class WebPluginManager
|
||||
|
||||
var plugin = await _webPluginService.GetByIdAsync(tenantId, id) ?? throw new ItemNotFoundException("Plugin not found");
|
||||
|
||||
if (plugin.System)
|
||||
await _webPluginService.DeleteAsync(tenantId, plugin.Id);
|
||||
|
||||
var storage = await GetPluginStorageAsync(tenantId);
|
||||
|
||||
await storage.DeleteDirectoryAsync(plugin.Name);
|
||||
|
||||
var key = GetCacheKey(tenantId);
|
||||
|
||||
_webPluginCache.Remove(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<List<DbWebPlugin>> GetSystemWebPluginsAsync()
|
||||
{
|
||||
var key = GetCacheKey(Tenant.DefaultTenant);
|
||||
|
||||
var systemPlugins = _webPluginCache.Get(key);
|
||||
|
||||
if (systemPlugins == null)
|
||||
{
|
||||
systemPlugins = await GetSystemWebPluginsFromStorageAsync();
|
||||
|
||||
_webPluginCache.Insert(key, systemPlugins);
|
||||
}
|
||||
|
||||
return systemPlugins;
|
||||
}
|
||||
|
||||
private async Task<List<DbWebPlugin>> GetSystemWebPluginsFromStorageAsync()
|
||||
{
|
||||
var systemPlugins = new List<DbWebPlugin>();
|
||||
|
||||
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)
|
||||
{
|
||||
try
|
||||
{
|
||||
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);
|
||||
|
||||
systemPlugins.Add(webPlugin);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.ErrorWithException(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))
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
await _webPluginService.DeleteAsync(tenantId, plugin.Id);
|
||||
var storage = await GetPluginStorageAsync(Tenant.DefaultTenant);
|
||||
|
||||
var storage = await _storageFactory.GetStorageAsync(tenantId, StorageModuleName);
|
||||
if (!await storage.IsDirectoryAsync(name))
|
||||
{
|
||||
throw new ItemNotFoundException("Plugin not found");
|
||||
}
|
||||
|
||||
await storage.DeleteDirectoryAsync(string.Empty, plugin.Name);
|
||||
await UpdateSystemWebPluginAsync(name, true);
|
||||
|
||||
await storage.DeleteDirectoryAsync(name);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ public class WebPluginSettings
|
||||
private long _maxSize;
|
||||
private string _extension;
|
||||
private string[] _allow;
|
||||
private string[] _assetExtensions;
|
||||
private string _systemUrl;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
@ -61,4 +63,26 @@ public class WebPluginSettings
|
||||
get => _allow ?? Array.Empty<string>();
|
||||
set => _allow = value;
|
||||
}
|
||||
|
||||
public string[] AssetExtensions
|
||||
{
|
||||
get => _assetExtensions ?? Array.Empty<string>();
|
||||
set => _assetExtensions = 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();
|
||||
}
|
||||
}
|
8
web/ASC.Web.Core/protos/web_plugin_cache_item.proto
Normal file
8
web/ASC.Web.Core/protos/web_plugin_cache_item.proto
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package ASC.Web.Core;
|
||||
|
||||
message WebPluginCacheItem {
|
||||
string key = 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user