diff --git a/build/Jenkinsfile b/build/Jenkinsfile index 056928b739..f6a9021f08 100644 --- a/build/Jenkinsfile +++ b/build/Jenkinsfile @@ -43,20 +43,20 @@ pipeline { stages { stage('Components') { steps { - sh "yarn install --frozen-lockfile && yarn build && cd ${env.WORKSPACE}/packages/asc-web-components && yarn test:coverage --ci --reporters=default --reporters=jest-junit || true" + sh "yarn install --frozen-lockfile && yarn build && cd ${env.WORKSPACE}/packages/components && yarn test:coverage --ci --reporters=default --reporters=jest-junit || true" } post { success { - junit 'packages/asc-web-components/junit.xml' + junit 'packages/components/junit.xml' publishHTML target: [ allowMissing : false, alwaysLinkToLastBuild: false, keepAll : true, - reportDir : 'packages/asc-web-components/coverage/lcov-report', + reportDir : 'packages/components/coverage/lcov-report', reportFiles : 'index.html', reportName : 'Unix Test Report' ] - publishCoverage adapters: [coberturaAdapter('packages/asc-web-components/coverage/cobertura-coverage.xml')] + publishCoverage adapters: [coberturaAdapter('packages/components/coverage/cobertura-coverage.xml')] } } } @@ -72,16 +72,16 @@ pipeline { stages { stage('Components') { steps { - bat "yarn install --frozen-lockfile && yarn build && cd ${env.WORKSPACE}\\packages\\asc-web-components && yarn test:coverage --ci --reporters=default --reporters=jest-junit || true" + bat "yarn install --frozen-lockfile && yarn build && cd ${env.WORKSPACE}\\packages\\components && yarn test:coverage --ci --reporters=default --reporters=jest-junit || true" } post { success { - junit 'packages\\asc-web-components\\junit.xml' + junit 'packages\\components\\junit.xml' publishHTML target: [ allowMissing : false, alwaysLinkToLastBuild: false, keepAll : true, - reportDir : 'packages\\asc-web-components\\coverage\\lcov-report', + reportDir : 'packages\\components\\coverage\\lcov-report', reportFiles : 'index.html', reportName : 'Windows Test Report' ] diff --git a/build/createMigrations.bat b/build/createMigrations.bat index e5726af891..1f7fcf9ca0 100644 --- a/build/createMigrations.bat +++ b/build/createMigrations.bat @@ -1,5 +1,6 @@ @echo "MIGRATIONS" @echo off -PUSHD %~dp0..\common\Tools\Migration.Creator -dotnet run --project Migration.Creator.csproj \ No newline at end of file +PUSHD %~dp0..\common\Tools\ASC.Migration.Creator +dotnet run --project ASC.Migration.Creator.csproj +pause \ No newline at end of file diff --git a/common/ASC.Api.Core/GlobalUsings.cs b/common/ASC.Api.Core/GlobalUsings.cs index c8b3fada04..298e86ee55 100644 --- a/common/ASC.Api.Core/GlobalUsings.cs +++ b/common/ASC.Api.Core/GlobalUsings.cs @@ -24,8 +24,6 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode -global using Microsoft.Extensions.DependencyInjection.Extensions; -global using System.Collections.Concurrent; global using System.ComponentModel; global using System.Globalization; global using System.Linq.Expressions; @@ -36,6 +34,7 @@ global using System.Runtime.Serialization; global using System.Security; global using System.Security.Authentication; global using System.Security.Claims; +global using System.Text; global using System.Text.Encodings.Web; global using System.Text.Json; global using System.Text.Json.Serialization; @@ -56,8 +55,8 @@ global using ASC.AuditTrail.Types; global using ASC.Common; global using ASC.Common.Caching; global using ASC.Common.DependencyInjection; +global using ASC.Common.Log; global using ASC.Common.Logging; -global using ASC.Common.Mapping; global using ASC.Common.Notify.Engine; global using ASC.Common.Threading; global using ASC.Common.Utils; @@ -119,6 +118,7 @@ global using Microsoft.AspNetCore.WebUtilities; global using Microsoft.EntityFrameworkCore; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection.Extensions; global using Microsoft.Extensions.Diagnostics.HealthChecks; global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; diff --git a/common/ASC.Api.Core/Middleware/WebhooksGlobalFilterAttribute.cs b/common/ASC.Api.Core/Middleware/WebhooksGlobalFilterAttribute.cs index e46dce71a5..6b03a2b28d 100644 --- a/common/ASC.Api.Core/Middleware/WebhooksGlobalFilterAttribute.cs +++ b/common/ASC.Api.Core/Middleware/WebhooksGlobalFilterAttribute.cs @@ -24,8 +24,6 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode -using System.Text; - namespace ASC.Api.Core.Middleware; [Scope] @@ -34,12 +32,14 @@ public class WebhooksGlobalFilterAttribute : ResultFilterAttribute, IDisposable private readonly MemoryStream _stream; private Stream _bodyStream; private readonly IWebhookPublisher _webhookPublisher; + private readonly ILogger _logger; private static readonly List _methodList = new List { "POST", "UPDATE", "DELETE" }; - public WebhooksGlobalFilterAttribute(IWebhookPublisher webhookPublisher) + public WebhooksGlobalFilterAttribute(IWebhookPublisher webhookPublisher, ILogger logger) { _stream = new MemoryStream(); _webhookPublisher = webhookPublisher; + _logger = logger; } public override void OnResultExecuting(ResultExecutingContext context) @@ -68,11 +68,18 @@ public class WebhooksGlobalFilterAttribute : ResultFilterAttribute, IDisposable await _stream.CopyToAsync(_bodyStream); context.HttpContext.Response.Body = _bodyStream; - var (method, routePattern) = GetData(context.HttpContext); + try + { + var (method, routePattern) = GetData(context.HttpContext); - var resultContent = Encoding.UTF8.GetString(_stream.ToArray()); - var eventName = $"method: {method}, route: {routePattern}"; - _webhookPublisher.Publish(eventName, resultContent); + var resultContent = Encoding.UTF8.GetString(_stream.ToArray()); + + await _webhookPublisher.PublishAsync(method, routePattern, resultContent); + } + catch (Exception e) + { + _logger.ErrorWithException(e); + } } } diff --git a/common/ASC.Core.Common/EF/Model/ModelBuilderWrapper.cs b/common/ASC.Core.Common/EF/Model/ModelBuilderWrapper.cs index e7a21b4270..be538f57e4 100644 --- a/common/ASC.Core.Common/EF/Model/ModelBuilderWrapper.cs +++ b/common/ASC.Core.Common/EF/Model/ModelBuilderWrapper.cs @@ -24,6 +24,8 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode +using Microsoft.EntityFrameworkCore.Metadata.Builders; + namespace ASC.Core.Common.EF.Model; public class ModelBuilderWrapper @@ -75,6 +77,11 @@ public class ModelBuilderWrapper return this; } + public EntityTypeBuilder Entity() where T : class + { + return ModelBuilder.Entity(); + } + public void AddDbFunction() { ModelBuilder diff --git a/common/ASC.Webhooks.Core/DbWorker.cs b/common/ASC.Webhooks.Core/DbWorker.cs index 1b73b7282c..3704f51bfe 100644 --- a/common/ASC.Webhooks.Core/DbWorker.cs +++ b/common/ASC.Webhooks.Core/DbWorker.cs @@ -30,117 +30,186 @@ namespace ASC.Webhooks.Core; public class DbWorker { private readonly IDbContextFactory _dbContextFactory; - private readonly TenantManager _tenantManager; - public DbWorker(IDbContextFactory dbContextFactory, TenantManager tenantManager) + private readonly TenantManager _tenantManager; + private readonly AuthContext _authContext; + + private int Tenant + { + get + { + return _tenantManager.GetCurrentTenant().Id; + } + } + + public DbWorker(IDbContextFactory dbContextFactory, TenantManager tenantManager, AuthContext authContext) { _dbContextFactory = dbContextFactory; - _tenantManager = tenantManager; - } - public void AddWebhookConfig(WebhooksConfig webhooksConfig) - { - webhooksConfig.TenantId = _tenantManager.GetCurrentTenant().Id; - - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); + _tenantManager = tenantManager; + _authContext = authContext; + } - var addObj = webhooksDbContext.WebhooksConfigs.Where(it => - it.SecretKey == webhooksConfig.SecretKey && - it.TenantId == webhooksConfig.TenantId && - it.Uri == webhooksConfig.Uri).FirstOrDefault(); - - if (addObj != null) - { - return; - } - - webhooksDbContext.WebhooksConfigs.Add(webhooksConfig); - webhooksDbContext.SaveChanges(); - } - - public int ConfigsNumber() + public async Task AddWebhookConfig(string name, string uri, string secretKey) { using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - return webhooksDbContext.WebhooksConfigs.Count(); + + var toAdd = new WebhooksConfig { TenantId = Tenant, Uri = uri, SecretKey = secretKey, Name = name }; + toAdd = await webhooksDbContext.AddOrUpdateAsync(r => r.WebhooksConfigs, toAdd); + await webhooksDbContext.SaveChangesAsync(); + + return toAdd; } - public List GetTenantWebhooks() + public async IAsyncEnumerable GetTenantWebhooks() + { + using var webhooksDbContext = _dbContextFactory.CreateDbContext(); + + var q = webhooksDbContext.WebhooksConfigs + .AsNoTracking() + .Where(it => it.TenantId == Tenant) + .AsAsyncEnumerable(); + + await foreach (var webhook in q) + { + yield return webhook; + } + } + + public IAsyncEnumerable GetWebhookConfigs() + { + var webhooksDbContext = _dbContextFactory.CreateDbContext(); + + return webhooksDbContext.WebhooksConfigs + .Where(t => t.TenantId == Tenant) + .AsAsyncEnumerable(); + } + + public async Task UpdateWebhookConfig(int id, string name, string uri, string key, bool? enabled) + { + using var webhooksDbContext = _dbContextFactory.CreateDbContext(); + + var updateObj = await webhooksDbContext.WebhooksConfigs + .Where(it => it.TenantId == Tenant && it.Id == id) + .FirstOrDefaultAsync(); + + if (updateObj != null) + { + if (!string.IsNullOrEmpty(uri)) + { + updateObj.Uri = uri; + } + + if (!string.IsNullOrEmpty(name)) + { + updateObj.Name = name; + } + + if (!string.IsNullOrEmpty(key)) + { + updateObj.SecretKey = key; + } + + if (enabled.HasValue) + { + updateObj.Enabled = enabled.Value; + } + + webhooksDbContext.WebhooksConfigs.Update(updateObj); + await webhooksDbContext.SaveChangesAsync(); + } + + return updateObj; + } + + public async Task RemoveWebhookConfig(int id) { var tenant = _tenantManager.GetCurrentTenant().Id; - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - return webhooksDbContext.WebhooksLogs.Where(it => it.TenantId == tenant) - .Select(t => new WebhooksLog - { - Uid = t.Uid, - CreationTime = t.CreationTime, - RequestPayload = t.RequestPayload, - RequestHeaders = t.RequestHeaders, - ResponsePayload = t.ResponsePayload, - ResponseHeaders = t.ResponseHeaders, - Status = t.Status - }).ToList(); - } - - public List GetWebhookConfigs(int tenant) - { - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - return webhooksDbContext.WebhooksConfigs.Where(t => t.TenantId == tenant).ToList(); - } - - public WebhookEntry ReadFromJournal(int id) - { - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - return webhooksDbContext.WebhooksLogs - .Where(it => it.Id == id) - .Join(webhooksDbContext.WebhooksConfigs, t => t.ConfigId, t => t.ConfigId, (payload, config) => new { payload, config }) - .Select(t => new WebhookEntry { Id = t.payload.Id, Payload = t.payload.RequestPayload, SecretKey = t.config.SecretKey, Uri = t.config.Uri }) - .OrderBy(t => t.Id).FirstOrDefault(); - } - - public void RemoveWebhookConfig(WebhooksConfig webhooksConfig) - { - webhooksConfig.TenantId = _tenantManager.GetCurrentTenant().Id; + using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - var removeObj = webhooksDbContext.WebhooksConfigs.Where(it => - it.SecretKey == webhooksConfig.SecretKey && - it.TenantId == webhooksConfig.TenantId && - it.Uri == webhooksConfig.Uri).FirstOrDefault(); + var removeObj = await webhooksDbContext.WebhooksConfigs + .Where(it => it.TenantId == tenant && it.Id == id) + .FirstOrDefaultAsync(); webhooksDbContext.WebhooksConfigs.Remove(removeObj); - webhooksDbContext.SaveChanges(); - } - - public void UpdateWebhookConfig(WebhooksConfig webhooksConfig) - { - webhooksConfig.TenantId = _tenantManager.GetCurrentTenant().Id; + await webhooksDbContext.SaveChangesAsync(); - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - var updateObj = webhooksDbContext.WebhooksConfigs.Where(it => - it.SecretKey == webhooksConfig.SecretKey && - it.TenantId == webhooksConfig.TenantId && - it.Uri == webhooksConfig.Uri).FirstOrDefault(); - - webhooksDbContext.WebhooksConfigs.Update(updateObj); - webhooksDbContext.SaveChanges(); - } - - public void UpdateWebhookJournal(int id, ProcessStatus status, string responsePayload, string responseHeaders, string requestHeaders) + return removeObj; + } + + public IAsyncEnumerable ReadJournal(int startIndex, int limit, DateTime? delivery, string hookname, string route) { - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - var webhook = webhooksDbContext.WebhooksLogs.Where(t => t.Id == id).FirstOrDefault(); + var webhooksDbContext = _dbContextFactory.CreateDbContext(); + + var q = webhooksDbContext.WebhooksLogs + .AsNoTracking() + .Where(r => r.TenantId == Tenant); + + if (delivery.HasValue) + { + var date = delivery.Value; + q = q.Where(r => r.Delivery == date); + } + + if (!string.IsNullOrEmpty(hookname)) + { + q = q.Where(r => r.Config.Name == hookname); + } + + if (!string.IsNullOrEmpty(route)) + { + q = q.Where(r => r.Route == route); + } + + if (startIndex != 0) + { + q = q.Skip(startIndex); + } + + if (limit != 0) + { + q = q.Take(limit); + } + + return q.OrderByDescending(t => t.Id).AsAsyncEnumerable(); + } + + public async Task ReadJournal(int id) + { + using var webhooksDbContext = _dbContextFactory.CreateDbContext(); + + return await webhooksDbContext.WebhooksLogs + .AsNoTracking() + .Where(it => it.Id == id) + .FirstOrDefaultAsync(); + } + + public async Task WriteToJournal(WebhooksLog webhook) + { + webhook.TenantId = _tenantManager.GetCurrentTenant().Id; + webhook.Uid = _authContext.CurrentAccount.ID; + + using var webhooksDbContext = _dbContextFactory.CreateDbContext(); + + var entity = await webhooksDbContext.WebhooksLogs.AddAsync(webhook); + await webhooksDbContext.SaveChangesAsync(); + + return entity.Entity; + } + + public async Task UpdateWebhookJournal(int id, int status, DateTime delivery, string requestHeaders, string responsePayload, string responseHeaders) + { + using var webhooksDbContext = _dbContextFactory.CreateDbContext(); + + var webhook = await webhooksDbContext.WebhooksLogs.Where(t => t.Id == id).FirstOrDefaultAsync(); webhook.Status = status; + webhook.RequestHeaders = requestHeaders; webhook.ResponsePayload = responsePayload; - webhook.ResponseHeaders = responseHeaders; - webhook.RequestHeaders = requestHeaders; - webhooksDbContext.WebhooksLogs.Update(webhook); - webhooksDbContext.SaveChanges(); - } + webhook.ResponseHeaders = responseHeaders; + webhook.Delivery = delivery; - public int WriteToJournal(WebhooksLog webhook) - { - using var webhooksDbContext = _dbContextFactory.CreateDbContext(); - var entity = webhooksDbContext.WebhooksLogs.Add(webhook); - webhooksDbContext.SaveChanges(); - return entity.Entity.Id; + webhooksDbContext.WebhooksLogs.Update(webhook); + await webhooksDbContext.SaveChangesAsync(); + + return webhook; } } \ No newline at end of file diff --git a/common/ASC.Webhooks.Core/EF/Context/WebhooksDbContext.cs b/common/ASC.Webhooks.Core/EF/Context/WebhooksDbContext.cs index cb436c8ad9..661ece604b 100644 --- a/common/ASC.Webhooks.Core/EF/Context/WebhooksDbContext.cs +++ b/common/ASC.Webhooks.Core/EF/Context/WebhooksDbContext.cs @@ -28,8 +28,8 @@ namespace ASC.Webhooks.Core.EF.Context; public class WebhooksDbContext : DbContext { - public virtual DbSet WebhooksConfigs { get; set; } - public virtual DbSet WebhooksLogs { get; set; } + public DbSet WebhooksConfigs { get; set; } + public DbSet WebhooksLogs { get; set; } public WebhooksDbContext(DbContextOptions options) : base(options) { } diff --git a/common/ASC.Webhooks.Core/EF/Model/WebhooksConfig.cs b/common/ASC.Webhooks.Core/EF/Model/WebhooksConfig.cs index b5832d00ed..2232cb3bf9 100644 --- a/common/ASC.Webhooks.Core/EF/Model/WebhooksConfig.cs +++ b/common/ASC.Webhooks.Core/EF/Model/WebhooksConfig.cs @@ -25,12 +25,20 @@ // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode namespace ASC.Webhooks.Core.EF.Model; -public partial class WebhooksConfig + +public class WebhooksConfig : BaseEntity { - public int ConfigId { get; set; } + public int Id { get; set; } + public string Name { get; set; } public string SecretKey { get; set; } public int TenantId { get; set; } - public string Uri { get; set; } + public string Uri { get; set; } + public bool Enabled { get; set; } + + public override object[] GetKeys() + { + return new object[] { Id }; + } } public static class WebhooksConfigExtension @@ -46,15 +54,18 @@ public static class WebhooksConfigExtension { modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.ConfigId }) - .HasName("PRIMARY"); + entity.HasKey(e => new { e.Id }) + .HasName("PRIMARY"); + + entity.HasIndex(e => e.TenantId) + .HasDatabaseName("tenant_id"); entity.ToTable("webhooks_config") .HasCharSet("utf8"); - entity.Property(e => e.ConfigId) + entity.Property(e => e.Id) .HasColumnType("int") - .HasColumnName("config_id"); + .HasColumnName("id"); entity.Property(e => e.TenantId) .HasColumnName("tenant_id") @@ -68,7 +79,17 @@ public static class WebhooksConfigExtension entity.Property(e => e.SecretKey) .HasMaxLength(50) .HasColumnName("secret_key") - .HasDefaultValueSql("''"); + .HasDefaultValueSql("''"); + + entity.Property(e => e.Name) + .HasMaxLength(50) + .HasColumnName("name") + .IsRequired(); + + entity.Property(e => e.Enabled) + .HasColumnName("enabled") + .HasDefaultValueSql("'1'") + .HasColumnType("tinyint(1)"); }); } @@ -76,14 +97,17 @@ public static class WebhooksConfigExtension { modelBuilder.Entity(entity => { - entity.HasKey(e => new { e.ConfigId }) + entity.HasKey(e => new { e.Id }) .HasName("PRIMARY"); - entity.ToTable("webhooks_config"); + entity.ToTable("webhooks_config"); + + entity.HasIndex(e => e.TenantId) + .HasDatabaseName("tenant_id"); - entity.Property(e => e.ConfigId) + entity.Property(e => e.Id) .HasColumnType("int") - .HasColumnName("config_id"); + .HasColumnName("id"); entity.Property(e => e.TenantId) .HasColumnName("tenant_id") @@ -97,7 +121,16 @@ public static class WebhooksConfigExtension entity.Property(e => e.SecretKey) .HasMaxLength(50) .HasColumnName("secret_key") - .HasDefaultValueSql("''"); + .HasDefaultValueSql("''"); + + entity.Property(e => e.Name) + .HasMaxLength(50) + .HasColumnName("name") + .IsRequired(); + + entity.Property(e => e.Enabled) + .HasColumnName("enabled") + .HasDefaultValueSql("true"); }); } } diff --git a/common/ASC.Webhooks.Core/EF/Model/WebhooksLog.cs b/common/ASC.Webhooks.Core/EF/Model/WebhooksLog.cs index 8766f3b17e..3daa62b4c1 100644 --- a/common/ASC.Webhooks.Core/EF/Model/WebhooksLog.cs +++ b/common/ASC.Webhooks.Core/EF/Model/WebhooksLog.cs @@ -26,25 +26,31 @@ namespace ASC.Webhooks.Core.EF.Model; -public partial class WebhooksLog +public class WebhooksLog { public int ConfigId { get; set; } public DateTime CreationTime { get; set; } - public string Event { get; set; } - public int Id { get; set; } + public int Id { get; set; } + public string Method { get; set; } + public string Route { get; set; } public string RequestHeaders { get; set; } public string RequestPayload { get; set; } public string ResponseHeaders { get; set; } public string ResponsePayload { get; set; } - public ProcessStatus Status { get; set; } + public int Status { get; set; } public int TenantId { get; set; } - public string Uid { get; set; } + public Guid Uid { get; set; } + public DateTime? Delivery { get; set; } + + public WebhooksConfig Config { get; set; } } public static class WebhooksPayloadExtension { public static ModelBuilderWrapper AddWebhooksLog(this ModelBuilderWrapper modelBuilder) - { + { + modelBuilder.Entity().Navigation(e => e.Config).AutoInclude(); + modelBuilder .Add(MySqlAddWebhooksLog, Provider.MySql) .Add(PgSqlAddWebhooksLog, Provider.PostgreSql); @@ -60,7 +66,10 @@ public static class WebhooksPayloadExtension .HasName("PRIMARY"); entity.ToTable("webhooks_logs") - .HasCharSet("utf8"); + .HasCharSet("utf8"); + + entity.HasIndex(e => e.TenantId) + .HasDatabaseName("tenant_id"); entity.Property(e => e.Id) .HasColumnType("int") @@ -72,9 +81,10 @@ public static class WebhooksPayloadExtension .HasColumnName("config_id"); entity.Property(e => e.Uid) - .HasColumnType("varchar") - .HasColumnName("uid") - .HasMaxLength(50); + .HasColumnName("uid") + .HasColumnType("varchar(36)") + .HasCharSet("utf8") + .UseCollation("utf8_general_ci"); entity.Property(e => e.TenantId) .HasColumnName("tenant_id") @@ -83,7 +93,9 @@ public static class WebhooksPayloadExtension entity.Property(e => e.RequestPayload) .IsRequired() .HasColumnName("request_payload") - .HasColumnType("json"); + .HasColumnType("text") + .HasCharSet("utf8") + .UseCollation("utf8_general_ci"); entity.Property(e => e.RequestHeaders) .HasColumnName("request_headers") @@ -91,25 +103,35 @@ public static class WebhooksPayloadExtension entity.Property(e => e.ResponsePayload) .HasColumnName("response_payload") - .HasColumnType("json"); + .HasColumnType("text") + .HasCharSet("utf8") + .UseCollation("utf8_general_ci"); entity.Property(e => e.ResponseHeaders) .HasColumnName("response_headers") .HasColumnType("json"); - entity.Property(e => e.Event) + entity.Property(e => e.Method) .HasColumnType("varchar") - .HasColumnName("event") + .HasColumnName("method") + .HasMaxLength(100); + + entity.Property(e => e.Route) + .HasColumnType("varchar") + .HasColumnName("route") .HasMaxLength(100); entity.Property(e => e.CreationTime) .HasColumnType("datetime") .HasColumnName("creation_time"); + entity.Property(e => e.Delivery) + .HasColumnType("datetime") + .HasColumnName("delivery"); + entity.Property(e => e.Status) - .HasColumnType("varchar") - .HasColumnName("status") - .HasMaxLength(50); + .HasColumnType("int") + .HasColumnName("status"); }); } @@ -120,7 +142,10 @@ public static class WebhooksPayloadExtension entity.HasKey(e => new { e.Id }) .HasName("PRIMARY"); - entity.ToTable("webhooks_logs"); + entity.ToTable("webhooks_logs"); + + entity.HasIndex(e => e.TenantId) + .HasDatabaseName("tenant_id"); entity.Property(e => e.Id) .HasColumnType("int") @@ -142,34 +167,40 @@ public static class WebhooksPayloadExtension entity.Property(e => e.RequestPayload) .IsRequired() - .HasColumnName("request_payload") - .HasColumnType("json"); + .HasColumnName("request_payload"); entity.Property(e => e.RequestHeaders) .HasColumnName("request_headers") .HasColumnType("json"); entity.Property(e => e.ResponsePayload) - .HasColumnName("response_payload") - .HasColumnType("json"); + .HasColumnName("response_payload"); entity.Property(e => e.ResponseHeaders) .HasColumnName("response_headers") .HasColumnType("json"); - entity.Property(e => e.Event) + entity.Property(e => e.Method) .HasColumnType("varchar") - .HasColumnName("event") + .HasColumnName("method") + .HasMaxLength(100); + + entity.Property(e => e.Route) + .HasColumnType("varchar") + .HasColumnName("route") .HasMaxLength(100); entity.Property(e => e.CreationTime) .HasColumnType("datetime") - .HasColumnName("creation_time"); + .HasColumnName("creation_time"); + + entity.Property(e => e.Delivery) + .HasColumnType("datetime") + .HasColumnName("delivery"); entity.Property(e => e.Status) - .HasColumnType("varchar") - .HasColumnName("status") - .HasMaxLength(50); + .HasColumnType("int") + .HasColumnName("status"); }); } } \ No newline at end of file diff --git a/common/ASC.Webhooks.Core/IWebhookPublisher.cs b/common/ASC.Webhooks.Core/IWebhookPublisher.cs index ec9c529c26..be00d4bd37 100644 --- a/common/ASC.Webhooks.Core/IWebhookPublisher.cs +++ b/common/ASC.Webhooks.Core/IWebhookPublisher.cs @@ -29,5 +29,6 @@ namespace ASC.Webhooks.Core; [Scope] public interface IWebhookPublisher { - public void Publish(string eventName, string requestPayload); + public Task PublishAsync(string method, string route, string requestPayload); + public Task PublishAsync(string method, string route, string requestPayload, int configId); } \ No newline at end of file diff --git a/common/ASC.Webhooks.Core/WebhookPublisher.cs b/common/ASC.Webhooks.Core/WebhookPublisher.cs index 42edf23d69..f1d459b825 100644 --- a/common/ASC.Webhooks.Core/WebhookPublisher.cs +++ b/common/ASC.Webhooks.Core/WebhookPublisher.cs @@ -30,51 +30,56 @@ namespace ASC.Webhooks.Core; public class WebhookPublisher : IWebhookPublisher { private readonly DbWorker _dbWorker; - private readonly TenantManager _tenantManager; private readonly ICacheNotify _webhookNotify; - + public WebhookPublisher( DbWorker dbWorker, - TenantManager tenantManager, ICacheNotify webhookNotify) { _dbWorker = dbWorker; - _tenantManager = tenantManager; _webhookNotify = webhookNotify; } - public void Publish(string eventName, string requestPayload) + public async Task PublishAsync(string method, string route, string requestPayload) { - var tenantId = _tenantManager.GetCurrentTenant().Id; - var webhookConfigs = _dbWorker.GetWebhookConfigs(tenantId); - - foreach (var config in webhookConfigs) + if (string.IsNullOrEmpty(requestPayload)) { - var webhooksLog = new WebhooksLog - { - Uid = Guid.NewGuid().ToString(), - TenantId = tenantId, - Event = eventName, - CreationTime = DateTime.UtcNow, - RequestPayload = requestPayload, - Status = ProcessStatus.InProcess, - ConfigId = config.ConfigId - }; - var DbId = _dbWorker.WriteToJournal(webhooksLog); + return; + } + + var webhookConfigs = _dbWorker.GetWebhookConfigs(); - var request = new WebhookRequest() - { - Id = DbId - }; - - _webhookNotify.Publish(request, CacheNotifyAction.Update); + await foreach (var config in webhookConfigs.Where(r => r.Enabled)) + { + _ = await PublishAsync(method, route, requestPayload, config.Id); } } -} -public enum ProcessStatus -{ - InProcess, - Success, - Failed + public async Task PublishAsync(string method, string route, string requestPayload, int configId) + { + if (string.IsNullOrEmpty(requestPayload)) + { + return null; + } + + var webhooksLog = new WebhooksLog + { + Method = method, + Route = route, + CreationTime = DateTime.UtcNow, + RequestPayload = requestPayload, + ConfigId = configId + }; + + var webhook = await _dbWorker.WriteToJournal(webhooksLog); + + var request = new WebhookRequest + { + Id = webhook.Id + }; + + _webhookNotify.Publish(request, CacheNotifyAction.Update); + + return webhook; + } } diff --git a/common/services/ASC.Webhooks.Service/ASC.Webhooks.Service.csproj b/common/services/ASC.Webhooks.Service/ASC.Webhooks.Service.csproj index 0b8cffcb95..0c58b87659 100644 --- a/common/services/ASC.Webhooks.Service/ASC.Webhooks.Service.csproj +++ b/common/services/ASC.Webhooks.Service/ASC.Webhooks.Service.csproj @@ -6,6 +6,10 @@ enable + + + + diff --git a/common/services/ASC.Webhooks.Service/GlobalUsings.cs b/common/services/ASC.Webhooks.Service/GlobalUsings.cs index 41aae62e4c..33df612814 100644 --- a/common/services/ASC.Webhooks.Service/GlobalUsings.cs +++ b/common/services/ASC.Webhooks.Service/GlobalUsings.cs @@ -37,9 +37,13 @@ global using ASC.Common.Log; global using ASC.Common.Utils; global using ASC.Web.Webhooks; global using ASC.Webhooks.Core; +global using ASC.Webhooks.Service; global using ASC.Webhooks.Service.Log; global using ASC.Webhooks.Service.Services; global using Microsoft.AspNetCore.Builder; global using Microsoft.Extensions.Hosting.WindowsServices; -global using Microsoft.Extensions.Logging; +global using Microsoft.Extensions.Logging; + +global using Polly; +global using Polly.Extensions.Http; \ No newline at end of file diff --git a/common/services/ASC.Webhooks.Service/Program.cs b/common/services/ASC.Webhooks.Service/Program.cs index 1171ef1184..b264c9e053 100644 --- a/common/services/ASC.Webhooks.Service/Program.cs +++ b/common/services/ASC.Webhooks.Service/Program.cs @@ -41,11 +41,20 @@ builder.Host.ConfigureDefault(args, (hostContext, config, env, path) => diHelper.TryAdd(); - services.AddHostedService(); - diHelper.TryAdd(); - services.AddHostedService(); - diHelper.TryAdd(); + diHelper.TryAdd(); + + services.AddHttpClient("webhook") + .SetHandlerLifetime(TimeSpan.FromMinutes(5)) + .AddPolicyHandler((s, request) => + { + var settings = s.GetRequiredService(); + + return HttpPolicyExtensions + .HandleTransientHttpError() + .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) + .WaitAndRetryAsync(settings.RepeatCount.HasValue ? settings.RepeatCount.Value : 5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + }); }); builder.WebHost.ConfigureDefaultKestrel(); diff --git a/common/services/ASC.Webhooks.Service/Services/WorkerService.cs b/common/services/ASC.Webhooks.Service/Services/WorkerService.cs index 0ef5b6d39b..03d1a01504 100644 --- a/common/services/ASC.Webhooks.Service/Services/WorkerService.cs +++ b/common/services/ASC.Webhooks.Service/Services/WorkerService.cs @@ -29,26 +29,36 @@ namespace ASC.Webhooks.Service.Services; [Singletone] public class WorkerService : BackgroundService { - private readonly ILogger _logger; - private readonly ConcurrentQueue _queue; + private readonly ILogger _logger; private readonly int? _threadCount = 10; private readonly WebhookSender _webhookSender; - private readonly TimeSpan _waitingPeriod; + private readonly TimeSpan _waitingPeriod; + private readonly ConcurrentQueue _queue; + private readonly ICacheNotify _webhookNotify; - public WorkerService(WebhookSender webhookSender, + public WorkerService( + ICacheNotify webhookNotify, + WebhookSender webhookSender, ILogger logger, - BuildQueueService buildQueueService, Settings settings) - { - _logger = logger; + { + _webhookNotify = webhookNotify; + _queue = new ConcurrentQueue(); + _logger = logger; _webhookSender = webhookSender; - _queue = buildQueueService.Queue; _threadCount = settings.ThreadCount; _waitingPeriod = TimeSpan.FromSeconds(5); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { + { + _webhookNotify.Subscribe(_queue.Enqueue, CacheNotifyAction.Update); + + stoppingToken.Register(() => + { + _webhookNotify.Unsubscribe(CacheNotifyAction.Update); + }); + while (!stoppingToken.IsCancellationRequested) { var queueSize = _queue.Count; @@ -62,7 +72,7 @@ public class WorkerService : BackgroundService continue; } - var tasks = new List(); + var tasks = new List(queueSize); var counter = 0; for (var i = 0; i < queueSize; i++) @@ -82,13 +92,13 @@ public class WorkerService : BackgroundService if (counter >= _threadCount) { - Task.WaitAll(tasks.ToArray()); + await Task.WhenAll(tasks); tasks.Clear(); counter = 0; } - } - - Task.WaitAll(tasks.ToArray()); + } + + await Task.WhenAll(tasks); _logger.DebugProcedureFinish(); } } diff --git a/common/services/ASC.Webhooks.Service/Settings.cs b/common/services/ASC.Webhooks.Service/Settings.cs index 5ade284f35..0c3754160e 100644 --- a/common/services/ASC.Webhooks.Service/Settings.cs +++ b/common/services/ASC.Webhooks.Service/Settings.cs @@ -37,7 +37,7 @@ public class Settings { var cfg = configuration.GetSetting("webhooks"); RepeatCount = cfg.RepeatCount ?? 5; - ThreadCount = cfg.ThreadCount ?? 1; + ThreadCount = cfg.ThreadCount ?? 10; } public int? RepeatCount { get; } public int? ThreadCount { get; } diff --git a/common/services/ASC.Webhooks.Service/WebhookSender.cs b/common/services/ASC.Webhooks.Service/WebhookSender.cs index f67d750a7e..2a0ad3284e 100644 --- a/common/services/ASC.Webhooks.Service/WebhookSender.cs +++ b/common/services/ASC.Webhooks.Service/WebhookSender.cs @@ -24,6 +24,8 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode +using System.Text.Json.Serialization; + namespace ASC.Webhooks.Service; [Singletone] @@ -31,15 +33,19 @@ public class WebhookSender { private readonly IHttpClientFactory _clientFactory; private readonly ILogger _log; - public int? RepeatCount { get; init; } - private readonly IServiceScopeFactory _scopeFactory; + private readonly IServiceScopeFactory _scopeFactory; + private readonly JsonSerializerOptions _jsonSerializerOptions; - public WebhookSender(ILoggerProvider options, IServiceScopeFactory scopeFactory, Settings settings, IHttpClientFactory clientFactory) + public WebhookSender(ILoggerProvider options, IServiceScopeFactory scopeFactory, IHttpClientFactory clientFactory) { _log = options.CreateLogger("ASC.Webhooks.Core"); _scopeFactory = scopeFactory; - RepeatCount = settings.RepeatCount; - _clientFactory = clientFactory; + _clientFactory = clientFactory; + _jsonSerializerOptions = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + IgnoreReadOnlyProperties = true + }; } public async Task Send(WebhookRequest webhookRequest, CancellationToken cancellationToken) @@ -47,82 +53,65 @@ public class WebhookSender using var scope = _scopeFactory.CreateScope(); var dbWorker = scope.ServiceProvider.GetRequiredService(); - var entry = dbWorker.ReadFromJournal(webhookRequest.Id); - var id = entry.Id; - var requestURI = entry.Uri; - var secretKey = entry.SecretKey; - var data = entry.Payload; - - var response = new HttpResponseMessage(); - var request = new HttpRequestMessage(); - - for (var i = 0; i < RepeatCount; i++) - { - try - { - request = new HttpRequestMessage(HttpMethod.Post, requestURI); - request.Headers.Add("Accept", "*/*"); - request.Headers.Add("Secret", "SHA256=" + GetSecretHash(secretKey, data)); - - request.Content = new StringContent( - data, - Encoding.UTF8, - "application/json"); - - var httpClient = _clientFactory.CreateClient(); - response = await httpClient.SendAsync(request, cancellationToken); - - if (response.IsSuccessStatusCode) - { - UpdateDb(dbWorker, id, response, request, ProcessStatus.Success); - _log.DebugResponse(response); - break; - } - else if (i == RepeatCount - 1) - { - UpdateDb(dbWorker, id, response, request, ProcessStatus.Failed); - _log.DebugResponse(response); - } - } - catch (Exception ex) - { - if (i == RepeatCount - 1) - { - UpdateDb(dbWorker, id, response, request, ProcessStatus.Failed); - } - - _log.ErrorWithException(ex); - continue; - } + var entry = await dbWorker.ReadJournal(webhookRequest.Id); + + var status = 0; + string responsePayload = null; + string responseHeaders = null; + string requestHeaders = null; + var delivery = DateTime.MinValue; + + try + { + var httpClient = _clientFactory.CreateClient("webhook"); + var request = new HttpRequestMessage(HttpMethod.Post, entry.Config.Uri) + { + Content = new StringContent(entry.RequestPayload, Encoding.UTF8, "application/json") + }; + + request.Headers.Add("Accept", "*/*"); + request.Headers.Add("Secret", "SHA256=" + GetSecretHash(entry.Config.SecretKey, entry.RequestPayload)); + requestHeaders = JsonSerializer.Serialize(request.Headers.ToDictionary(r => r.Key, v => v.Value), _jsonSerializerOptions); + + var response = await httpClient.SendAsync(request, cancellationToken); + + status = (int)response.StatusCode; + responseHeaders = JsonSerializer.Serialize(response.Headers.ToDictionary(r => r.Key, v => v.Value), _jsonSerializerOptions); + responsePayload = await response.Content.ReadAsStringAsync(); + delivery = DateTime.UtcNow; + + _log.DebugResponse(response); + } + catch (HttpRequestException e) + { + if (e.StatusCode.HasValue) + { + status = (int)e.StatusCode.Value; + } + responsePayload = e.Message; + delivery = DateTime.UtcNow; + + _log.ErrorWithException(e); + } + catch (Exception e) + { + _log.ErrorWithException(e); + } + + if (delivery != DateTime.MinValue) + { + await dbWorker.UpdateWebhookJournal(entry.Id, status, delivery, requestHeaders, responsePayload, responseHeaders); } } private string GetSecretHash(string secretKey, string body) - { - string computedSignature; + { var secretBytes = Encoding.UTF8.GetBytes(secretKey); using (var hasher = new HMACSHA256(secretBytes)) { var data = Encoding.UTF8.GetBytes(body); - computedSignature = BitConverter.ToString(hasher.ComputeHash(data)); + return BitConverter.ToString(hasher.ComputeHash(data)); } - - return computedSignature; - } - - private void UpdateDb(DbWorker dbWorker, int id, HttpResponseMessage response, HttpRequestMessage request, ProcessStatus status) - { - var responseHeaders = JsonSerializer.Serialize(response.Headers.ToDictionary(r => r.Key, v => v.Value)); - var requestHeaders = JsonSerializer.Serialize(request.Headers.ToDictionary(r => r.Key, v => v.Value)); - string responsePayload; - - using (var streamReader = new StreamReader(response.Content.ReadAsStream())) - { - var responseContent = streamReader.ReadToEnd(); - responsePayload = JsonSerializer.Serialize(responseContent); - } - - dbWorker.UpdateWebhookJournal(id, status, responsePayload, responseHeaders, requestHeaders); } } \ No newline at end of file diff --git a/config/appsettings.json b/config/appsettings.json index 20ba7a0b04..c914bff490 100644 --- a/config/appsettings.json +++ b/config/appsettings.json @@ -53,7 +53,7 @@ "enabled": "true" }, "version": { - "number": "11.5.0", + "number": "1.0.0", "release": { "date": "", "sign": "" diff --git a/migrations/mysql/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.Designer.cs b/migrations/mysql/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.Designer.cs new file mode 100644 index 0000000000..518e40c72f --- /dev/null +++ b/migrations/mysql/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.Designer.cs @@ -0,0 +1,163 @@ +// +using System; +using ASC.Webhooks.Core.EF.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ASC.Migrations.MySql.Migrations.WebhooksDb +{ + [DbContext(typeof(WebhooksDbContext))] + [Migration("20220818144209_WebhooksDbContext_Upgrade1")] + partial class WebhooksDbContext_Upgrade1 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + b.Property("Enabled") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasColumnName("enabled") + .HasDefaultValueSql("'1'"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("name"); + + b.Property("SecretKey") + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("secret_key") + .HasDefaultValueSql("''"); + + b.Property("TenantId") + .HasColumnType("int unsigned") + .HasColumnName("tenant_id"); + + b.Property("Uri") + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("uri") + .HasDefaultValueSql("''"); + + b.HasKey("Id") + .HasName("PRIMARY"); + + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + + b.ToTable("webhooks_config", (string)null); + + b.HasAnnotation("MySql:CharSet", "utf8"); + }); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + b.Property("ConfigId") + .HasColumnType("int") + .HasColumnName("config_id"); + + b.Property("CreationTime") + .HasColumnType("datetime") + .HasColumnName("creation_time"); + + b.Property("Delivery") + .HasColumnType("datetime") + .HasColumnName("delivery"); + + b.Property("Method") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("method"); + + b.Property("RequestHeaders") + .HasColumnType("json") + .HasColumnName("request_headers"); + + b.Property("RequestPayload") + .IsRequired() + .HasColumnType("text") + .HasColumnName("request_payload") + .UseCollation("utf8_general_ci") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("ResponseHeaders") + .HasColumnType("json") + .HasColumnName("response_headers"); + + b.Property("ResponsePayload") + .HasColumnType("text") + .HasColumnName("response_payload") + .UseCollation("utf8_general_ci") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.Property("Route") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("route"); + + b.Property("Status") + .HasColumnType("int") + .HasColumnName("status"); + + b.Property("TenantId") + .HasColumnType("int unsigned") + .HasColumnName("tenant_id"); + + b.Property("Uid") + .IsRequired() + .HasColumnType("varchar(36)") + .HasColumnName("uid") + .UseCollation("utf8_general_ci") + .HasAnnotation("MySql:CharSet", "utf8"); + + b.HasKey("Id") + .HasName("PRIMARY"); + + b.HasIndex("ConfigId"); + + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + + b.ToTable("webhooks_logs", (string)null); + + b.HasAnnotation("MySql:CharSet", "utf8"); + }); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksLog", b => + { + b.HasOne("ASC.Webhooks.Core.EF.Model.WebhooksConfig", "Config") + .WithMany() + .HasForeignKey("ConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Config"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/migrations/mysql/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.cs b/migrations/mysql/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.cs new file mode 100644 index 0000000000..2cc14406df --- /dev/null +++ b/migrations/mysql/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.cs @@ -0,0 +1,151 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ASC.Migrations.MySql.Migrations.WebhooksDb +{ + public partial class WebhooksDbContext_Upgrade1 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "config_id", + table: "webhooks_config", + newName: "id"); + + migrationBuilder.UpdateData( + table: "webhooks_logs", + keyColumn: "uid", + keyValue: null, + column: "uid", + value: ""); + + migrationBuilder.AlterColumn( + name: "uid", + table: "webhooks_logs", + type: "varchar(36)", + nullable: false, + collation: "utf8_general_ci", + oldClrType: typeof(string), + oldType: "varchar(50)", + oldMaxLength: 50, + oldNullable: true) + .Annotation("MySql:CharSet", "utf8") + .OldAnnotation("MySql:CharSet", "utf8"); + + migrationBuilder.AlterColumn( + name: "status", + table: "webhooks_logs", + type: "int", + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(50)", + oldMaxLength: 50) + .OldAnnotation("MySql:CharSet", "utf8"); + + migrationBuilder.AddColumn( + name: "delivery", + table: "webhooks_logs", + type: "datetime", + nullable: true); + + migrationBuilder.AddColumn( + name: "enabled", + table: "webhooks_config", + type: "tinyint(1)", + nullable: false, + defaultValueSql: "'1'"); + + migrationBuilder.AddColumn( + name: "name", + table: "webhooks_config", + type: "varchar(50)", + maxLength: 50, + nullable: false, + defaultValue: "") + .Annotation("MySql:CharSet", "utf8"); + + migrationBuilder.CreateIndex( + name: "IX_webhooks_logs_config_id", + table: "webhooks_logs", + column: "config_id"); + + migrationBuilder.CreateIndex( + name: "tenant_id", + table: "webhooks_logs", + column: "tenant_id"); + + migrationBuilder.CreateIndex( + name: "tenant_id", + table: "webhooks_config", + column: "tenant_id"); + + migrationBuilder.AddForeignKey( + name: "FK_webhooks_logs_webhooks_config_config_id", + table: "webhooks_logs", + column: "config_id", + principalTable: "webhooks_config", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_webhooks_logs_webhooks_config_config_id", + table: "webhooks_logs"); + + migrationBuilder.DropIndex( + name: "IX_webhooks_logs_config_id", + table: "webhooks_logs"); + + migrationBuilder.DropIndex( + name: "tenant_id", + table: "webhooks_logs"); + + migrationBuilder.DropIndex( + name: "tenant_id", + table: "webhooks_config"); + + migrationBuilder.DropColumn( + name: "delivery", + table: "webhooks_logs"); + + migrationBuilder.DropColumn( + name: "enabled", + table: "webhooks_config"); + + migrationBuilder.DropColumn( + name: "name", + table: "webhooks_config"); + + migrationBuilder.RenameColumn( + name: "id", + table: "webhooks_config", + newName: "config_id"); + + migrationBuilder.AlterColumn( + name: "uid", + table: "webhooks_logs", + type: "varchar(50)", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "varchar(36)", + oldCollation: "utf8_general_ci") + .Annotation("MySql:CharSet", "utf8") + .OldAnnotation("MySql:CharSet", "utf8"); + + migrationBuilder.AlterColumn( + name: "status", + table: "webhooks_logs", + type: "varchar(50)", + maxLength: 50, + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:CharSet", "utf8"); + } + } +} diff --git a/migrations/mysql/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs b/migrations/mysql/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs index 53e7ba2bfd..13a232a63a 100644 --- a/migrations/mysql/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs +++ b/migrations/mysql/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs @@ -16,15 +16,27 @@ namespace ASC.Migrations.MySql.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("ProductVersion", "6.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksConfig", b => { - b.Property("ConfigId") + b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") - .HasColumnName("config_id"); + .HasColumnName("id"); + + b.Property("Enabled") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasColumnName("enabled") + .HasDefaultValueSql("'1'"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("name"); b.Property("SecretKey") .ValueGeneratedOnAdd() @@ -44,9 +56,12 @@ namespace ASC.Migrations.MySql.Migrations .HasColumnName("uri") .HasDefaultValueSql("''"); - b.HasKey("ConfigId") + b.HasKey("Id") .HasName("PRIMARY"); + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + b.ToTable("webhooks_config", (string)null); b.HasAnnotation("MySql:CharSet", "utf8"); @@ -67,10 +82,14 @@ namespace ASC.Migrations.MySql.Migrations .HasColumnType("datetime") .HasColumnName("creation_time"); - b.Property("Event") + b.Property("Delivery") + .HasColumnType("datetime") + .HasColumnName("delivery"); + + b.Property("Method") .HasMaxLength(100) .HasColumnType("varchar(100)") - .HasColumnName("event"); + .HasColumnName("method"); b.Property("RequestHeaders") .HasColumnType("json") @@ -78,21 +97,28 @@ namespace ASC.Migrations.MySql.Migrations b.Property("RequestPayload") .IsRequired() - .HasColumnType("json") - .HasColumnName("request_payload"); + .HasColumnType("text") + .HasColumnName("request_payload") + .UseCollation("utf8_general_ci") + .HasAnnotation("MySql:CharSet", "utf8"); b.Property("ResponseHeaders") .HasColumnType("json") .HasColumnName("response_headers"); b.Property("ResponsePayload") - .HasColumnType("json") - .HasColumnName("response_payload"); + .HasColumnType("text") + .HasColumnName("response_payload") + .UseCollation("utf8_general_ci") + .HasAnnotation("MySql:CharSet", "utf8"); - b.Property("Status") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("varchar(50)") + b.Property("Route") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("route"); + + b.Property("Status") + .HasColumnType("int") .HasColumnName("status"); b.Property("TenantId") @@ -100,17 +126,35 @@ namespace ASC.Migrations.MySql.Migrations .HasColumnName("tenant_id"); b.Property("Uid") - .HasMaxLength(50) - .HasColumnType("varchar(50)") - .HasColumnName("uid"); + .IsRequired() + .HasColumnType("varchar(36)") + .HasColumnName("uid") + .UseCollation("utf8_general_ci") + .HasAnnotation("MySql:CharSet", "utf8"); b.HasKey("Id") .HasName("PRIMARY"); + b.HasIndex("ConfigId"); + + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + b.ToTable("webhooks_logs", (string)null); b.HasAnnotation("MySql:CharSet", "utf8"); }); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksLog", b => + { + b.HasOne("ASC.Webhooks.Core.EF.Model.WebhooksConfig", "Config") + .WithMany() + .HasForeignKey("ConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Config"); + }); #pragma warning restore 612, 618 } } diff --git a/migrations/postgre/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.Designer.cs b/migrations/postgre/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.Designer.cs new file mode 100644 index 0000000000..c94244b6b9 --- /dev/null +++ b/migrations/postgre/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.Designer.cs @@ -0,0 +1,158 @@ +// +using System; +using ASC.Webhooks.Core.EF.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace ASC.Migrations.PostgreSql.Migrations.WebhooksDb +{ + [DbContext(typeof(WebhooksDbContext))] + [Migration("20220818144209_WebhooksDbContext_Upgrade1")] + partial class WebhooksDbContext_Upgrade1 + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "6.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Enabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasColumnName("enabled") + .HasDefaultValueSql("true"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + + b.Property("SecretKey") + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("secret_key") + .HasDefaultValueSql("''"); + + b.Property("TenantId") + .HasColumnType("int unsigned") + .HasColumnName("tenant_id"); + + b.Property("Uri") + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("uri") + .HasDefaultValueSql("''"); + + b.HasKey("Id") + .HasName("PRIMARY"); + + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + + b.ToTable("webhooks_config", (string)null); + }); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ConfigId") + .HasColumnType("int") + .HasColumnName("config_id"); + + b.Property("CreationTime") + .HasColumnType("datetime") + .HasColumnName("creation_time"); + + b.Property("Delivery") + .HasColumnType("datetime") + .HasColumnName("delivery"); + + b.Property("Method") + .HasMaxLength(100) + .HasColumnType("varchar") + .HasColumnName("method"); + + b.Property("RequestHeaders") + .HasColumnType("json") + .HasColumnName("request_headers"); + + b.Property("RequestPayload") + .IsRequired() + .HasColumnType("text") + .HasColumnName("request_payload"); + + b.Property("ResponseHeaders") + .HasColumnType("json") + .HasColumnName("response_headers"); + + b.Property("ResponsePayload") + .HasColumnType("text") + .HasColumnName("response_payload"); + + b.Property("Route") + .HasMaxLength(100) + .HasColumnType("varchar") + .HasColumnName("route"); + + b.Property("Status") + .HasColumnType("int") + .HasColumnName("status"); + + b.Property("TenantId") + .HasColumnType("int unsigned") + .HasColumnName("tenant_id"); + + b.Property("Uid") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar") + .HasColumnName("uid"); + + b.HasKey("Id") + .HasName("PRIMARY"); + + b.HasIndex("ConfigId"); + + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + + b.ToTable("webhooks_logs", (string)null); + }); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksLog", b => + { + b.HasOne("ASC.Webhooks.Core.EF.Model.WebhooksConfig", "Config") + .WithMany() + .HasForeignKey("ConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Config"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/migrations/postgre/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.cs b/migrations/postgre/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.cs new file mode 100644 index 0000000000..75c35a3790 --- /dev/null +++ b/migrations/postgre/WebhooksDbContext/20220818144209_WebhooksDbContext_Upgrade1.cs @@ -0,0 +1,138 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ASC.Migrations.PostgreSql.Migrations.WebhooksDb +{ + public partial class WebhooksDbContext_Upgrade1 : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "config_id", + table: "webhooks_config", + newName: "id"); + + migrationBuilder.AlterColumn( + name: "uid", + table: "webhooks_logs", + type: "varchar", + maxLength: 50, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "varchar", + oldMaxLength: 50, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "status", + table: "webhooks_logs", + type: "int", + nullable: false, + oldClrType: typeof(string), + oldType: "varchar", + oldMaxLength: 50); + + migrationBuilder.AddColumn( + name: "delivery", + table: "webhooks_logs", + type: "datetime", + nullable: true); + + migrationBuilder.AddColumn( + name: "enabled", + table: "webhooks_config", + type: "boolean", + nullable: false, + defaultValueSql: "true"); + + migrationBuilder.AddColumn( + name: "name", + table: "webhooks_config", + type: "character varying(50)", + maxLength: 50, + nullable: false, + defaultValue: ""); + + migrationBuilder.CreateIndex( + name: "IX_webhooks_logs_config_id", + table: "webhooks_logs", + column: "config_id"); + + migrationBuilder.CreateIndex( + name: "tenant_id", + table: "webhooks_logs", + column: "tenant_id"); + + migrationBuilder.CreateIndex( + name: "tenant_id", + table: "webhooks_config", + column: "tenant_id"); + + migrationBuilder.AddForeignKey( + name: "FK_webhooks_logs_webhooks_config_config_id", + table: "webhooks_logs", + column: "config_id", + principalTable: "webhooks_config", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_webhooks_logs_webhooks_config_config_id", + table: "webhooks_logs"); + + migrationBuilder.DropIndex( + name: "IX_webhooks_logs_config_id", + table: "webhooks_logs"); + + migrationBuilder.DropIndex( + name: "tenant_id", + table: "webhooks_logs"); + + migrationBuilder.DropIndex( + name: "tenant_id", + table: "webhooks_config"); + + migrationBuilder.DropColumn( + name: "delivery", + table: "webhooks_logs"); + + migrationBuilder.DropColumn( + name: "enabled", + table: "webhooks_config"); + + migrationBuilder.DropColumn( + name: "name", + table: "webhooks_config"); + + migrationBuilder.RenameColumn( + name: "id", + table: "webhooks_config", + newName: "config_id"); + + migrationBuilder.AlterColumn( + name: "uid", + table: "webhooks_logs", + type: "varchar", + maxLength: 50, + nullable: true, + oldClrType: typeof(string), + oldType: "varchar", + oldMaxLength: 50); + + migrationBuilder.AlterColumn( + name: "status", + table: "webhooks_logs", + type: "varchar", + maxLength: 50, + nullable: false, + oldClrType: typeof(int), + oldType: "int"); + } + } +} diff --git a/migrations/postgre/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs b/migrations/postgre/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs index 07fbed37ca..0c5af441ed 100644 --- a/migrations/postgre/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs +++ b/migrations/postgre/WebhooksDbContext/WebhooksDbContextModelSnapshot.cs @@ -18,17 +18,29 @@ namespace ASC.Migrations.PostgreSql.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) - .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("ProductVersion", "6.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 63); modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksConfig", b => { - b.Property("ConfigId") + b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") - .HasColumnName("config_id") + .HasColumnName("id") .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + b.Property("Enabled") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasColumnName("enabled") + .HasDefaultValueSql("true"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name"); + b.Property("SecretKey") .ValueGeneratedOnAdd() .HasMaxLength(50) @@ -47,9 +59,12 @@ namespace ASC.Migrations.PostgreSql.Migrations .HasColumnName("uri") .HasDefaultValueSql("''"); - b.HasKey("ConfigId") + b.HasKey("Id") .HasName("PRIMARY"); + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + b.ToTable("webhooks_config", (string)null); }); @@ -69,10 +84,14 @@ namespace ASC.Migrations.PostgreSql.Migrations .HasColumnType("datetime") .HasColumnName("creation_time"); - b.Property("Event") + b.Property("Delivery") + .HasColumnType("datetime") + .HasColumnName("delivery"); + + b.Property("Method") .HasMaxLength(100) .HasColumnType("varchar") - .HasColumnName("event"); + .HasColumnName("method"); b.Property("RequestHeaders") .HasColumnType("json") @@ -80,7 +99,7 @@ namespace ASC.Migrations.PostgreSql.Migrations b.Property("RequestPayload") .IsRequired() - .HasColumnType("json") + .HasColumnType("text") .HasColumnName("request_payload"); b.Property("ResponseHeaders") @@ -88,13 +107,16 @@ namespace ASC.Migrations.PostgreSql.Migrations .HasColumnName("response_headers"); b.Property("ResponsePayload") - .HasColumnType("json") + .HasColumnType("text") .HasColumnName("response_payload"); - b.Property("Status") - .IsRequired() - .HasMaxLength(50) + b.Property("Route") + .HasMaxLength(100) .HasColumnType("varchar") + .HasColumnName("route"); + + b.Property("Status") + .HasColumnType("int") .HasColumnName("status"); b.Property("TenantId") @@ -102,6 +124,7 @@ namespace ASC.Migrations.PostgreSql.Migrations .HasColumnName("tenant_id"); b.Property("Uid") + .IsRequired() .HasMaxLength(50) .HasColumnType("varchar") .HasColumnName("uid"); @@ -109,8 +132,24 @@ namespace ASC.Migrations.PostgreSql.Migrations b.HasKey("Id") .HasName("PRIMARY"); + b.HasIndex("ConfigId"); + + b.HasIndex("TenantId") + .HasDatabaseName("tenant_id"); + b.ToTable("webhooks_logs", (string)null); }); + + modelBuilder.Entity("ASC.Webhooks.Core.EF.Model.WebhooksLog", b => + { + b.HasOne("ASC.Webhooks.Core.EF.Model.WebhooksConfig", "Config") + .WithMany() + .HasForeignKey("ConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Config"); + }); #pragma warning restore 612, 618 } } diff --git a/products/ASC.Files/Core/Core/FileStorageService.cs b/products/ASC.Files/Core/Core/FileStorageService.cs index 50d60217f0..44d5b06317 100644 --- a/products/ASC.Files/Core/Core/FileStorageService.cs +++ b/products/ASC.Files/Core/Core/FileStorageService.cs @@ -238,8 +238,21 @@ public class FileStorageService //: IFileStorageService })); } - public async Task> GetFolderItemsAsync(T parentId, int from, int count, FilterType filterType, bool subjectGroup, string subject, string searchText, - bool searchInContent, bool withSubfolders, OrderBy orderBy, SearchArea searchArea = SearchArea.Active, bool withoutTags = false, IEnumerable tagNames = null, bool withoutMe = false) + public async Task> GetFolderItemsAsync( + T parentId, + int from, + int count, + FilterType filterType, + bool subjectGroup, + string subject, + string searchText, + bool searchInContent, + bool withSubfolders, + OrderBy orderBy, + SearchArea searchArea = SearchArea.Active, + bool withoutTags = false, + IEnumerable tagNames = null, + bool withoutMe = false) { var subjectId = string.IsNullOrEmpty(subject) ? Guid.Empty : new Guid(subject); diff --git a/products/ASC.Files/Server/Api/FoldersController.cs b/products/ASC.Files/Server/Api/FoldersController.cs index da0cc721bc..f6a724d676 100644 --- a/products/ASC.Files/Server/Api/FoldersController.cs +++ b/products/ASC.Files/Server/Api/FoldersController.cs @@ -122,7 +122,7 @@ public abstract class FoldersController : ApiControllerBase /// Filter type /// Folder contents [HttpGet("{folderId}", Order = 1)] - public async Task> GetFolderAsync(T folderId, Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetFolderAsync(T folderId, Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { var folder = await _foldersControllerHelper.GetFolderAsync(folderId, userIdOrGroupId, filterType, searchInContent, withsubfolders); @@ -223,7 +223,7 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// Common folder contents [HttpGet("@common")] - public async Task> GetCommonFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetCommonFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return await _foldersControllerHelperInt.GetFolderAsync(await _globalFolderHelper.FolderCommonAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders); } @@ -235,7 +235,7 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// Favorites contents [HttpGet("@favorites")] - public async Task> GetFavoritesFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetFavoritesFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return await _foldersControllerHelperInt.GetFolderAsync(await _globalFolderHelper.FolderFavoritesAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders); } @@ -249,13 +249,13 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// My folder contents [HttpGet("@my")] - public Task> GetMyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public Task> GetMyFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return _foldersControllerHelperInt.GetFolderAsync(_globalFolderHelper.FolderMy, userIdOrGroupId, filterType, searchInContent, withsubfolders); } [HttpGet("@privacy")] - public async Task> GetPrivacyFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetPrivacyFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { if (PrivacyRoomSettings.IsAvailable()) { @@ -274,7 +274,7 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// Projects folder contents [HttpGet("@projects")] - public async Task> GetProjectsFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetProjectsFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return await _foldersControllerHelperString.GetFolderAsync(await _globalFolderHelper.GetFolderProjectsAsync(), userIdOrGroupId, filterType, searchInContent, withsubfolders); } @@ -286,15 +286,15 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// Recent contents [HttpGet("@recent")] - public async Task> GetRecentFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetRecentFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return await _foldersControllerHelperInt.GetFolderAsync(await _globalFolderHelper.FolderRecentAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders); } [HttpGet("@root")] - public async IAsyncEnumerable> GetRootFoldersAsync(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders, bool withoutTrash, bool searchInContent, bool withoutAdditionalFolder) + public async IAsyncEnumerable> GetRootFoldersAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? withsubfolders, bool? withoutTrash, bool? searchInContent, bool? withoutAdditionalFolder) { - var foldersIds = _foldersControllerHelperInt.GetRootFoldersIdsAsync(withoutTrash, withoutAdditionalFolder); + var foldersIds = _foldersControllerHelperInt.GetRootFoldersIdsAsync(withoutTrash ?? false, withoutAdditionalFolder ?? false); await foreach (var folder in foldersIds) { @@ -311,7 +311,7 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// Shared folder contents [HttpGet("@share")] - public async Task> GetShareFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetShareFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return await _foldersControllerHelperInt.GetFolderAsync(await _globalFolderHelper.FolderShareAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders); } @@ -323,7 +323,7 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// Templates contents [HttpGet("@templates")] - public async Task> GetTemplatesFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public async Task> GetTemplatesFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return await _foldersControllerHelperInt.GetFolderAsync(await _globalFolderHelper.FolderTemplatesAsync, userIdOrGroupId, filterType, searchInContent, withsubfolders); } @@ -337,7 +337,7 @@ public class FoldersControllerCommon : ApiControllerBase /// Folders /// Trash folder contents [HttpGet("@trash")] - public Task> GetTrashFolderAsync(Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withsubfolders) + public Task> GetTrashFolderAsync(Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withsubfolders) { return _foldersControllerHelperInt.GetFolderAsync(Convert.ToInt32(_globalFolderHelper.FolderTrash), userIdOrGroupId, filterType, searchInContent, withsubfolders); } diff --git a/products/ASC.Files/Server/Api/VirtualRoomsController.cs b/products/ASC.Files/Server/Api/VirtualRoomsController.cs index 9321430811..1bbf1f481d 100644 --- a/products/ASC.Files/Server/Api/VirtualRoomsController.cs +++ b/products/ASC.Files/Server/Api/VirtualRoomsController.cs @@ -182,7 +182,7 @@ public abstract class VirtualRoomsController : ApiControllerBase /// Room content /// [HttpGet("rooms/{id}")] - public async Task> GetRoomAsync(T id, Guid userOrGroupId, FilterType filterType, bool searchInContent, bool withSubFolders) + public async Task> GetRoomAsync(T id, Guid? userOrGroupId, FilterType? filterType, bool? searchInContent, bool? withSubFolders) { ErrorIfNotDocSpace(); @@ -669,8 +669,7 @@ public class VirtualRoomsCommonController : ApiControllerBase /// Virtual Rooms content /// [HttpGet("rooms")] - public async Task> GetRoomsFolderAsync(RoomType type, string subjectId, bool searchInContent, bool withSubfolders, SearchArea searchArea, bool withoutTags, string tags, - bool withoutMe) + public async Task> GetRoomsFolderAsync(RoomType? type, string subjectId, bool? searchInContent, bool? withSubfolders, SearchArea? searchArea, bool? withoutTags, string tags, bool? withoutMe) { ErrorIfNotDocSpace(); @@ -700,7 +699,7 @@ public class VirtualRoomsCommonController : ApiControllerBase var filterValue = _apiContext.FilterValue; var content = await _fileStorageService.GetFolderItemsAsync(parentId, startIndex, count, filterType, false, subjectId, filterValue, - searchInContent, withSubfolders, orderBy, searchArea, withoutTags, tagNames, withoutMe); + searchInContent ?? false, withSubfolders ?? false, orderBy, searchArea ?? SearchArea.Active, withoutTags ?? false, tagNames, withoutMe ?? false); var dto = await _folderContentDtoHelper.GetAsync(content, startIndex); diff --git a/products/ASC.Files/Server/Helpers/FoldersControllerHelper.cs b/products/ASC.Files/Server/Helpers/FoldersControllerHelper.cs index 73135a59e2..593cd72668 100644 --- a/products/ASC.Files/Server/Helpers/FoldersControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FoldersControllerHelper.cs @@ -77,9 +77,9 @@ public class FoldersControllerHelper : FilesHelperBase return await _folderDtoHelper.GetAsync(folder); } - public async Task> GetFolderAsync(T folderId, Guid userIdOrGroupId, FilterType filterType, bool searchInContent, bool withSubFolders) + public async Task> GetFolderAsync(T folderId, Guid? userIdOrGroupId, FilterType? filterType, bool? searchInContent, bool? withSubFolders) { - var folderContentWrapper = await ToFolderContentWrapperAsync(folderId, userIdOrGroupId, filterType, searchInContent, withSubFolders); + var folderContentWrapper = await ToFolderContentWrapperAsync(folderId, userIdOrGroupId ?? Guid.Empty, filterType ?? FilterType.None, searchInContent ?? false, withSubFolders ?? false); return folderContentWrapper.NotFoundIfNull(); } @@ -175,8 +175,7 @@ public class FoldersControllerHelper : FilesHelperBase } var startIndex = Convert.ToInt32(_apiContext.StartIndex); - var items = await _fileStorageService.GetFolderItemsAsync(folderId, startIndex, Convert.ToInt32(_apiContext.Count), filterType, - filterType == FilterType.ByUser, userIdOrGroupId.ToString(), _apiContext.FilterValue, searchInContent, withSubFolders, orderBy); + var items = await _fileStorageService.GetFolderItemsAsync(folderId, startIndex, Convert.ToInt32(_apiContext.Count), filterType, filterType == FilterType.ByUser, userIdOrGroupId.ToString(), _apiContext.FilterValue, searchInContent, withSubFolders, orderBy); return await _folderContentDtoHelper.GetAsync(items, startIndex); } diff --git a/web/ASC.Web.Api/Api/Settings/VersionController.cs b/web/ASC.Web.Api/Api/Settings/VersionController.cs index f0a169fd42..f723eede18 100644 --- a/web/ASC.Web.Api/Api/Settings/VersionController.cs +++ b/web/ASC.Web.Api/Api/Settings/VersionController.cs @@ -51,9 +51,9 @@ public class VersionController : BaseSettingsController [AllowAnonymous] [AllowNotPayment] [HttpGet("version/build")] - public Task GetBuildVersionsAsync() + public async Task GetBuildVersionsAsync() { - return _buildVersion.GetCurrentBuildVersionAsync(); + return await _buildVersion.GetCurrentBuildVersionAsync(); } [HttpGet("version")] diff --git a/web/ASC.Web.Api/Api/Settings/WebhooksController.cs b/web/ASC.Web.Api/Api/Settings/WebhooksController.cs index 5b87bf6d35..d5ec7b3bdc 100644 --- a/web/ASC.Web.Api/Api/Settings/WebhooksController.cs +++ b/web/ASC.Web.Api/Api/Settings/WebhooksController.cs @@ -27,82 +27,136 @@ namespace ASC.Web.Api.Controllers.Settings; public class WebhooksController : BaseSettingsController -{ - private readonly DbWorker _webhookDbWorker; - - public WebhooksController( +{ + private readonly ApiContext _context; + private readonly PermissionContext _permissionContext; + private readonly DbWorker _webhookDbWorker; + private readonly IMapper _mapper; + private readonly WebhookPublisher _webhookPublisher; + + public WebhooksController( + ApiContext context, + PermissionContext permissionContext, ApiContext apiContext, WebItemManager webItemManager, IMemoryCache memoryCache, DbWorker dbWorker, - IHttpContextAccessor httpContextAccessor) : base(apiContext, memoryCache, webItemManager, httpContextAccessor) - { - _webhookDbWorker = dbWorker; - } + IHttpContextAccessor httpContextAccessor, + IMapper mapper, + WebhookPublisher webhookPublisher) + : base(apiContext, memoryCache, webItemManager, httpContextAccessor) + { + _context = context; + _permissionContext = permissionContext; + _webhookDbWorker = dbWorker; + _mapper = mapper; + _webhookPublisher = webhookPublisher; + } + + [HttpGet("webhook")] + public async IAsyncEnumerable GetTenantWebhooks() + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + + await foreach (var w in _webhookDbWorker.GetTenantWebhooks()) + { + yield return _mapper.Map(w); + } + } - /// - /// Add new config for webhooks - /// [HttpPost("webhook")] - public void CreateWebhook(WebhooksConfig model) - { - if (model.Uri == null) - { - throw new ArgumentNullException("Uri"); - } + public async Task CreateWebhook(WebhooksConfigRequestsDto model) + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + + ArgumentNullException.ThrowIfNull(model.Uri); + ArgumentNullException.ThrowIfNull(model.SecretKey); - if (model.SecretKey == null) - { - throw new ArgumentNullException("SecretKey"); - } - - _webhookDbWorker.AddWebhookConfig(model); + var webhook = await _webhookDbWorker.AddWebhookConfig(model.Name, model.Uri, model.SecretKey); + + return _mapper.Map(webhook); } - /// - /// Update config for webhooks - /// [HttpPut("webhook")] - public void UpdateWebhook(WebhooksConfig model) - { - if (model.Uri == null) - { - throw new ArgumentNullException("Uri"); - } + public async Task UpdateWebhook(WebhooksConfigRequestsDto model) + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + + ArgumentNullException.ThrowIfNull(model.Uri); + ArgumentNullException.ThrowIfNull(model.SecretKey); - if (model.SecretKey == null) - { - throw new ArgumentNullException("SecretKey"); - } - - _webhookDbWorker.UpdateWebhookConfig(model); + var webhook = await _webhookDbWorker.UpdateWebhookConfig(model.Id, model.Name, model.Uri, model.SecretKey, model.Enabled); + + return _mapper.Map(webhook); } - /// - /// Remove config for webhooks - /// [HttpDelete("webhook")] - public void RemoveWebhook(WebhooksConfig model) - { - if (model.Uri == null) - { - throw new ArgumentNullException("Uri"); - } + public async Task RemoveWebhook(int id) + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); - if (model.SecretKey == null) - { - throw new ArgumentNullException("SecretKey"); - } - - _webhookDbWorker.RemoveWebhookConfig(model); + var webhook = await _webhookDbWorker.RemoveWebhookConfig(id); + + return _mapper.Map(webhook); } - /// - /// Read Webhooks history for actual tenant - /// - [HttpGet("webhooks")] - public List TenantWebhooks() - { - return _webhookDbWorker.GetTenantWebhooks(); + [HttpGet("webhooks/log")] + public async IAsyncEnumerable GetJournal(DateTime? delivery, string hookname, string route) + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + var startIndex = Convert.ToInt32(_context.StartIndex); + var count = Convert.ToInt32(_context.Count); + + await foreach (var j in _webhookDbWorker.ReadJournal(startIndex, count, delivery, hookname, route)) + { + yield return _mapper.Map(j); + } + } + + [HttpPut("webhook/{id}/retry")] + public async Task RetryWebhook(int id) + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + + if (id == 0) + { + throw new ArgumentException(nameof(id)); + } + + var item = await _webhookDbWorker.ReadJournal(id); + + if (item == null) + { + throw new ItemNotFoundException(); + } + + if (item.Status >= 200 && item.Status <= 299 || item.Status == 0) + { + throw new HttpException(HttpStatusCode.Forbidden); + } + + var result = await _webhookPublisher.PublishAsync(item.Method, item.Route, item.RequestPayload, item.ConfigId); + + return _mapper.Map(result); + } + + [HttpPut("webhook/retry")] + public async IAsyncEnumerable RetryWebhooks(WebhookRetryRequestsDto model) + { + _permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings); + + foreach (var id in model.Ids) + { + var item = await _webhookDbWorker.ReadJournal(id); + + if (item == null || item.Status >= 200 && item.Status <= 299 || item.Status == 0) + { + continue; + } + + var result = await _webhookPublisher.PublishAsync(item.Method, item.Route, item.RequestPayload, item.ConfigId); + + yield return _mapper.Map(result); + } } } \ No newline at end of file diff --git a/common/services/ASC.Webhooks.Service/Services/BuildQueueService.cs b/web/ASC.Web.Api/ApiModels/RequestsDto/WebhookRetryRequestsDto.cs similarity index 64% rename from common/services/ASC.Webhooks.Service/Services/BuildQueueService.cs rename to web/ASC.Web.Api/ApiModels/RequestsDto/WebhookRetryRequestsDto.cs index 69d3065767..ea8591d9c3 100644 --- a/common/services/ASC.Webhooks.Service/Services/BuildQueueService.cs +++ b/web/ASC.Web.Api/ApiModels/RequestsDto/WebhookRetryRequestsDto.cs @@ -1,56 +1,32 @@ -// (c) Copyright Ascensio System SIA 2010-2022 -// -// This program is a free software product. -// You can redistribute it and/or modify it under the terms -// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software -// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended -// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of -// any third-party rights. -// -// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see -// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html -// -// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. -// -// The interactive user interfaces in modified source and object code versions of the Program must -// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. -// -// Pursuant to Section 7(b) of the License you must retain the original Product logo when -// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under -// trademark law for use of our trademarks. -// -// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing -// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 -// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode - -namespace ASC.Webhooks.Service.Services; - -[Singletone] -public class BuildQueueService : BackgroundService -{ - internal readonly ConcurrentQueue Queue; - private readonly ICacheNotify _webhookNotify; - - public BuildQueueService(ICacheNotify webhookNotify) - { - _webhookNotify = webhookNotify; - Queue = new ConcurrentQueue(); - } - public void BuildWebhooksQueue(WebhookRequest request) - { - Queue.Enqueue(request); - } - - protected override Task ExecuteAsync(CancellationToken stoppingToken) - { - _webhookNotify.Subscribe(BuildWebhooksQueue, CacheNotifyAction.Update); - - stoppingToken.Register(() => - { - _webhookNotify.Unsubscribe(CacheNotifyAction.Update); - }); - - return Task.CompletedTask; - } -} \ No newline at end of file +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Web.Api.ApiModels.RequestsDto; + +public class WebhookRetryRequestsDto +{ + public List Ids { get; set; } +} diff --git a/common/ASC.Webhooks.Core/EF/Model/WebhookEntry.cs b/web/ASC.Web.Api/ApiModels/RequestsDto/WebhooksConfigRequestsDto.cs similarity index 74% rename from common/ASC.Webhooks.Core/EF/Model/WebhookEntry.cs rename to web/ASC.Web.Api/ApiModels/RequestsDto/WebhooksConfigRequestsDto.cs index d47799c99f..12656d073e 100644 --- a/common/ASC.Webhooks.Core/EF/Model/WebhookEntry.cs +++ b/web/ASC.Web.Api/ApiModels/RequestsDto/WebhooksConfigRequestsDto.cs @@ -1,53 +1,36 @@ -// (c) Copyright Ascensio System SIA 2010-2022 -// -// This program is a free software product. -// You can redistribute it and/or modify it under the terms -// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software -// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended -// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of -// any third-party rights. -// -// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see -// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html -// -// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. -// -// The interactive user interfaces in modified source and object code versions of the Program must -// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. -// -// Pursuant to Section 7(b) of the License you must retain the original Product logo when -// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under -// trademark law for use of our trademarks. -// -// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing -// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 -// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode - -namespace ASC.Webhooks.Core.EF.Model; - -public class WebhookEntry -{ - public int Id { get; set; } - public string Payload { get; set; } - public string SecretKey { get; set; } - public string Uri { get; set; } - public override bool Equals(object other) - { - var toCompareWith = other as WebhookEntry; - if (toCompareWith == null) - { - return false; - } - - return Id == toCompareWith.Id && - Payload == toCompareWith.Payload && - Uri == toCompareWith.Uri && - SecretKey == toCompareWith.SecretKey; - } - - public override int GetHashCode() - { - return Id.GetHashCode(); - } -} +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Web.Api.ApiModels.RequestsDto; + +public class WebhooksConfigRequestsDto +{ + public int Id { get; set; } + public string Name { get; set; } + public string Uri { get; set; } + public string SecretKey { get; set; } + public bool? Enabled { get; set; } +} diff --git a/web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksConfigDto.cs b/web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksConfigDto.cs new file mode 100644 index 0000000000..1fc80d61a5 --- /dev/null +++ b/web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksConfigDto.cs @@ -0,0 +1,34 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Web.Api.ApiModels.ResponseDto; + +public class WebhooksConfigDto : IMapFrom +{ + public string Uri { get; set; } + public string SecretKey { get; set; } + public bool Enabled { get; set; } +} diff --git a/web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksLogDto.cs b/web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksLogDto.cs new file mode 100644 index 0000000000..8c91ad336c --- /dev/null +++ b/web/ASC.Web.Api/ApiModels/ResponseDto/WebhooksLogDto.cs @@ -0,0 +1,42 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Web.Api.ApiModels.ResponseDto; + +public class WebhooksLogDto : IMapFrom +{ + public int Id { get; set; } + public string ConfigName { get; set; } + public DateTime CreationTime { get; set; } + public string Method { get; set; } + public string Route { get; set; } + public string RequestHeaders { get; set; } + public string RequestPayload { get; set; } + public string ResponseHeaders { get; set; } + public string ResponsePayload { get; set; } + public int Status { get; set; } + public DateTime? Delivery { get; set; } +} diff --git a/web/ASC.Web.Api/Core/BuildVersion.cs b/web/ASC.Web.Api/Core/BuildVersion.cs index 71ed65b66e..d9900039ca 100644 --- a/web/ASC.Web.Api/Core/BuildVersion.cs +++ b/web/ASC.Web.Api/Core/BuildVersion.cs @@ -29,7 +29,9 @@ namespace ASC.Api.Settings; [Scope] public class BuildVersion { - public string CommunityServer { get; set; } + public string DocSpace { get; set; } + + public string CommunityServer { get; set; } //old public string DocumentServer { get; set; } @@ -54,8 +56,10 @@ public class BuildVersion } public async Task GetCurrentBuildVersionAsync() - { - CommunityServer = GetCommunityVersion(); + { + CommunityServer = "12.0.0"; + + DocSpace = GetDocSpaceVersion(); DocumentServer = await GetDocumentVersionAsync(); MailServer = GetMailServerVersion(); XmppServer = GetXmppServerVersion(); @@ -63,9 +67,9 @@ public class BuildVersion return this; } - private string GetCommunityVersion() + private string GetDocSpaceVersion() { - return _configuration["version:number"] ?? "8.5.0"; + return _configuration["version:number"] ?? "1.0.0"; } private Task GetDocumentVersionAsync() diff --git a/web/ASC.Web.Api/GlobalUsings.cs b/web/ASC.Web.Api/GlobalUsings.cs index 4a0042ecaf..bdaae9b7bf 100644 --- a/web/ASC.Web.Api/GlobalUsings.cs +++ b/web/ASC.Web.Api/GlobalUsings.cs @@ -62,6 +62,7 @@ global using ASC.Common.Radicale.Core; global using ASC.Common.Security.Authorizing; global using ASC.Common.Threading; global using ASC.Common.Utils; +global using ASC.Common.Web; global using ASC.Core; global using ASC.Core.Billing; global using ASC.Core.Common.Configuration;