Merge branch 'develop' into feature/shared-redesign-third-party
This commit is contained in:
commit
efde1f00a9
@ -101,6 +101,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Migration", "common\ASC
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ActiveDirectory", "common\ASC.ActiveDirectory\ASC.ActiveDirectory.csproj", "{9F81862F-303D-467F-8DC9-044BE2CCF329}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.EventBus.ActiveMQ", "common\ASC.EventBus.ActiveMQ\ASC.EventBus.ActiveMQ.csproj", "{86916EF2-4A1B-441C-B673-EB0F68EC9C3A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -287,6 +289,10 @@ Global
|
||||
{9F81862F-303D-467F-8DC9-044BE2CCF329}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9F81862F-303D-467F-8DC9-044BE2CCF329}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9F81862F-303D-467F-8DC9-044BE2CCF329}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{86916EF2-4A1B-441C-B673-EB0F68EC9C3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{86916EF2-4A1B-441C-B673-EB0F68EC9C3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{86916EF2-4A1B-441C-B673-EB0F68EC9C3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{86916EF2-4A1B-441C-B673-EB0F68EC9C3A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -10,6 +10,7 @@
|
||||
"common\\ASC.Data.Encryption\\ASC.Data.Encryption.csproj",
|
||||
"common\\ASC.Data.Reassigns\\ASC.Data.Reassigns.csproj",
|
||||
"common\\ASC.Data.Storage\\ASC.Data.Storage.csproj",
|
||||
"common\\ASC.EventBus.ActiveMQ\\ASC.EventBus.ActiveMQ.csproj",
|
||||
"common\\ASC.EventBus.Extensions.Logger\\ASC.EventBus.Extensions.Logger.csproj",
|
||||
"common\\ASC.EventBus.RabbitMQ\\ASC.EventBus.RabbitMQ.csproj",
|
||||
"common\\ASC.EventBus\\ASC.EventBus.csproj",
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\web\ASC.Web.Core\ASC.Web.Core.csproj" />
|
||||
<ProjectReference Include="..\ASC.EventBus.ActiveMQ\ASC.EventBus.ActiveMQ.csproj" />
|
||||
<ProjectReference Include="..\ASC.EventBus.Extensions.Logger\ASC.EventBus.Extensions.Logger.csproj" />
|
||||
<ProjectReference Include="..\ASC.EventBus.RabbitMQ\ASC.EventBus.RabbitMQ.csproj" />
|
||||
<ProjectReference Include="..\ASC.Webhooks.Core\ASC.Webhooks.Core.csproj" />
|
||||
|
@ -54,6 +54,8 @@ public static class ConfigurationManagerExtension
|
||||
.AddJsonFile($"kafka.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("rabbitmq.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"rabbitmq.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("activemq.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"activemq.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile("redis.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"redis.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
|
||||
|
||||
|
@ -75,6 +75,7 @@ public static class ServiceCollectionExtension
|
||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||
|
||||
var rabbitMQConfiguration = configuration.GetSection("RabbitMQ").Get<RabbitMQSettings>();
|
||||
var activeMQConfiguration = configuration.GetSection("ActiveMQ").Get<ActiveMQSettings>();
|
||||
|
||||
if (rabbitMQConfiguration != null)
|
||||
{
|
||||
@ -154,6 +155,54 @@ public static class ServiceCollectionExtension
|
||||
|
||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, serializer, subscriptionClientName, retryCount);
|
||||
});
|
||||
}
|
||||
else if (activeMQConfiguration != null)
|
||||
{
|
||||
services.AddSingleton<IActiveMQPersistentConnection>(sp =>
|
||||
{
|
||||
var cfg = sp.GetRequiredService<IConfiguration>();
|
||||
|
||||
var logger = sp.GetRequiredService<ILogger<DefaultActiveMQPersistentConnection>>();
|
||||
|
||||
var factory = new Apache.NMS.NMSConnectionFactory(activeMQConfiguration.Uri);
|
||||
|
||||
var retryCount = 5;
|
||||
|
||||
if (!string.IsNullOrEmpty(cfg["core:eventBus:connectRetryCount"]))
|
||||
{
|
||||
retryCount = int.Parse(cfg["core:eventBus:connectRetryCount"]);
|
||||
}
|
||||
|
||||
return new DefaultActiveMQPersistentConnection(factory, logger, retryCount);
|
||||
});
|
||||
|
||||
services.AddSingleton<IEventBus, EventBusActiveMQ>(sp =>
|
||||
{
|
||||
var cfg = sp.GetRequiredService<IConfiguration>();
|
||||
|
||||
var activeMQPersistentConnection = sp.GetRequiredService<IActiveMQPersistentConnection>();
|
||||
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||
var logger = sp.GetRequiredService<ILogger<EventBusActiveMQ>>();
|
||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||
|
||||
var serializer = new EventBus.Serializers.ProtobufSerializer();
|
||||
|
||||
var subscriptionClientName = "asc_event_bus_default_queue";
|
||||
|
||||
if (!string.IsNullOrEmpty(cfg["core:eventBus:subscriptionClientName"]))
|
||||
{
|
||||
subscriptionClientName = cfg["core:eventBus:subscriptionClientName"];
|
||||
}
|
||||
|
||||
var retryCount = 5;
|
||||
|
||||
if (!string.IsNullOrEmpty(cfg["core:eventBus:connectRetryCount"]))
|
||||
{
|
||||
retryCount = int.Parse(cfg["core:eventBus:connectRetryCount"]);
|
||||
}
|
||||
|
||||
return new EventBusActiveMQ(activeMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, serializer, subscriptionClientName, retryCount);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -144,3 +144,7 @@ global using StackExchange.Redis.Extensions.Core.Configuration;
|
||||
global using StackExchange.Redis.Extensions.Newtonsoft;
|
||||
|
||||
global using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
||||
global using ASC.Common.Caching.Settings;
|
||||
global using ASC.EventBus.ActiveMQ;
|
||||
|
||||
|
@ -49,15 +49,20 @@ public class TenantStatusFilter : IResourceFilter
|
||||
{
|
||||
context.Result = new StatusCodeResult((int)HttpStatusCode.NotFound);
|
||||
_logger.WarningTenantNotFound();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (tenant.Status == TenantStatus.RemovePending || tenant.Status == TenantStatus.Suspended)
|
||||
{
|
||||
if (tenant.Status == TenantStatus.Suspended &&
|
||||
context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor &&
|
||||
controllerActionDescriptor.EndpointMetadata.OfType<AllowSuspendedAttribute>().Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.Result = new StatusCodeResult((int)HttpStatusCode.NotFound);
|
||||
_logger.WarningTenantIsNotRemoved(tenant.Id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -67,6 +72,7 @@ public class TenantStatusFilter : IResourceFilter
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
|
||||
_logger.WarningTenantStatus(tenant.Id, tenant.Status);
|
||||
return;
|
||||
|
@ -30,4 +30,10 @@ namespace ASC.Web.Api.Routing;
|
||||
public class AllowNotPaymentAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
public class AllowSuspendedAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
@ -232,17 +232,4 @@ public class RabbitMQCache<T> : IDisposable, ICacheNotify<T> where T : IMessage<
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class RabbitMQSettings
|
||||
{
|
||||
public string HostName { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string VirtualHost { get; set; }
|
||||
public string Uri { get; set; }
|
||||
public bool EnableSsl { get; set; }
|
||||
public string SslServerName { get; set; }
|
||||
public string SslCertPath { get; set; }
|
||||
}
|
||||
}
|
31
common/ASC.Common/Caching/Settings/ActiveMQSettings.cs
Normal file
31
common/ASC.Common/Caching/Settings/ActiveMQSettings.cs
Normal file
@ -0,0 +1,31 @@
|
||||
// (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.Common.Caching.Settings;
|
||||
public class ActiveMQSettings
|
||||
{
|
||||
public string Uri { get; set; }
|
||||
}
|
39
common/ASC.Common/Caching/Settings/RabbitMQSettings.cs
Normal file
39
common/ASC.Common/Caching/Settings/RabbitMQSettings.cs
Normal file
@ -0,0 +1,39 @@
|
||||
// (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.Common.Caching;
|
||||
public class RabbitMQSettings
|
||||
{
|
||||
public string HostName { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string VirtualHost { get; set; }
|
||||
public string Uri { get; set; }
|
||||
public bool EnableSsl { get; set; }
|
||||
public string SslServerName { get; set; }
|
||||
public string SslCertPath { get; set; }
|
||||
}
|
@ -45,6 +45,8 @@ public class TariffServiceStorage
|
||||
Notify = notify;
|
||||
Notify.Subscribe((i) =>
|
||||
{
|
||||
Cache.Insert(TariffService.GetTariffNeedToUpdateCacheKey(i.TenantId), "update", _cacheExpiration);
|
||||
|
||||
Cache.Remove(TariffService.GetTariffCacheKey(i.TenantId));
|
||||
Cache.Remove(TariffService.GetBillingUrlCacheKey(i.TenantId));
|
||||
Cache.Remove(TariffService.GetBillingPaymentCacheKey(i.TenantId)); // clear all payments
|
||||
@ -169,7 +171,11 @@ public class TariffService : ITariffService
|
||||
{
|
||||
tariff = GetBillingInfo(tenantId) ?? CreateDefault();
|
||||
tariff = CalculateTariff(tenantId, tariff);
|
||||
tariffId = tariff.Id;
|
||||
|
||||
if (string.IsNullOrEmpty(_cache.Get<string>(GetTariffNeedToUpdateCacheKey(tenantId))))
|
||||
{
|
||||
tariffId = tariff.Id;
|
||||
}
|
||||
|
||||
if (_billingClient.Configured && withRequestToPaymentSystem)
|
||||
{
|
||||
@ -210,9 +216,9 @@ public class TariffService : ITariffService
|
||||
if (SaveBillingInfo(tenantId, asynctariff))
|
||||
{
|
||||
asynctariff = CalculateTariff(tenantId, asynctariff);
|
||||
tariff = asynctariff;
|
||||
tariffId = asynctariff.Id;
|
||||
}
|
||||
|
||||
tariffId = asynctariff.Id;
|
||||
}
|
||||
catch (BillingNotFoundException)
|
||||
{
|
||||
@ -237,9 +243,9 @@ public class TariffService : ITariffService
|
||||
if (SaveBillingInfo(tenantId, asynctariff))
|
||||
{
|
||||
asynctariff = CalculateTariff(tenantId, asynctariff);
|
||||
tariff = asynctariff;
|
||||
tariffId = asynctariff.Id;
|
||||
}
|
||||
|
||||
tariffId = asynctariff.Id;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
@ -367,6 +373,11 @@ public class TariffService : ITariffService
|
||||
return $"{tenantId}:tariff";
|
||||
}
|
||||
|
||||
internal static string GetTariffNeedToUpdateCacheKey(int tenantId)
|
||||
{
|
||||
return $"{tenantId}:update";
|
||||
}
|
||||
|
||||
internal static string GetBillingUrlCacheKey(int tenantId)
|
||||
{
|
||||
return $"{tenantId}:billing:urls";
|
||||
|
20
common/ASC.EventBus.ActiveMQ/ASC.EventBus.ActiveMQ.csproj
Normal file
20
common/ASC.EventBus.ActiveMQ/ASC.EventBus.ActiveMQ.csproj
Normal file
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Apache.NMS.AMQP" Version="2.0.0" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ASC.Common\ASC.Common.csproj" />
|
||||
<ProjectReference Include="..\ASC.EventBus\ASC.EventBus.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -0,0 +1,175 @@
|
||||
// (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
|
||||
|
||||
using ASC.EventBus.ActiveMQ.Log;
|
||||
|
||||
namespace ASC.EventBus.ActiveMQ;
|
||||
|
||||
public class DefaultActiveMQPersistentConnection
|
||||
: IActiveMQPersistentConnection
|
||||
{
|
||||
private readonly IConnectionFactory _connectionFactory;
|
||||
private readonly ILogger<DefaultActiveMQPersistentConnection> _logger;
|
||||
private readonly int _retryCount;
|
||||
private IConnection _connection;
|
||||
private bool _disposed;
|
||||
readonly object sync_root = new object();
|
||||
|
||||
public DefaultActiveMQPersistentConnection(IConnectionFactory connectionFactory, ILogger<DefaultActiveMQPersistentConnection> logger, int retryCount = 5)
|
||||
{
|
||||
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_retryCount = retryCount;
|
||||
}
|
||||
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _connection != null && _connection.IsStarted && !_disposed;
|
||||
}
|
||||
}
|
||||
|
||||
public ISession CreateSession()
|
||||
{
|
||||
return CreateSession(AcknowledgementMode.AutoAcknowledge);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
|
||||
try
|
||||
{
|
||||
_connection.ExceptionListener -= OnExceptionListener;
|
||||
_connection.ConnectionInterruptedListener -= OnConnectionInterruptedListener;
|
||||
_connection.ConnectionResumedListener -= OnConnectionResumedListener;
|
||||
|
||||
_connection.Dispose();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.CriticalDefaultActiveMQPersistentConnection(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExceptionListener(Exception exception)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.WarningActiveMQConnectionThrowException();
|
||||
|
||||
TryConnect();
|
||||
}
|
||||
|
||||
private void OnConnectionResumedListener()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.WarningActiveMQConnectionThrowException();
|
||||
|
||||
TryConnect();
|
||||
}
|
||||
|
||||
private void OnConnectionInterruptedListener()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.WarningActiveMQConnectionThrowException();
|
||||
|
||||
TryConnect();
|
||||
}
|
||||
|
||||
public bool TryConnect()
|
||||
{
|
||||
_logger.InformationActiveMQTryingConnect();
|
||||
|
||||
lock (sync_root)
|
||||
{
|
||||
var policy = Policy.Handle<SocketException>()
|
||||
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
||||
{
|
||||
_logger.WarningActiveMQCouldNotConnect(time.TotalSeconds, ex);
|
||||
}
|
||||
);
|
||||
|
||||
policy.Execute(() =>
|
||||
{
|
||||
_connection = _connectionFactory
|
||||
.CreateConnection();
|
||||
_connection.Start();
|
||||
});
|
||||
|
||||
if (IsConnected)
|
||||
{
|
||||
_connection.ExceptionListener += OnExceptionListener;
|
||||
_connection.ConnectionInterruptedListener += OnConnectionInterruptedListener;
|
||||
_connection.ConnectionResumedListener += OnConnectionResumedListener;
|
||||
|
||||
if (_connection is Apache.NMS.AMQP.NmsConnection)
|
||||
{
|
||||
var hostname = ((Apache.NMS.AMQP.NmsConnection)_connection).ConnectionInfo.ConfiguredUri.Host;
|
||||
|
||||
_logger.InformationActiveMQAcquiredPersistentConnection(hostname);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.CriticalActiveMQCouldNotBeCreated();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ISession CreateSession(AcknowledgementMode acknowledgementMode)
|
||||
{
|
||||
if (!IsConnected)
|
||||
{
|
||||
throw new InvalidOperationException("No ActiveMQ connections are available to perform this action");
|
||||
}
|
||||
|
||||
return _connection.CreateSession(acknowledgementMode);
|
||||
}
|
||||
}
|
363
common/ASC.EventBus.ActiveMQ/EventBusActiveMQ.cs
Normal file
363
common/ASC.EventBus.ActiveMQ/EventBusActiveMQ.cs
Normal file
@ -0,0 +1,363 @@
|
||||
// (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.EventBus.ActiveMQ;
|
||||
|
||||
public class EventBusActiveMQ : IEventBus, IDisposable
|
||||
{
|
||||
const string EXCHANGE_NAME = "asc_event_bus";
|
||||
const string AUTOFAC_SCOPE_NAME = "asc_event_bus";
|
||||
|
||||
private readonly ILogger<EventBusActiveMQ> _logger;
|
||||
private readonly IEventBusSubscriptionsManager _subsManager;
|
||||
private readonly ILifetimeScope _autofac;
|
||||
|
||||
private static ConcurrentQueue<Guid> _rejectedEvents;
|
||||
private readonly IActiveMQPersistentConnection _persistentConnection;
|
||||
private readonly IIntegrationEventSerializer _serializer;
|
||||
private ISession _consumerSession;
|
||||
|
||||
private readonly List<IMessageConsumer> _consumers;
|
||||
|
||||
private readonly int _retryCount;
|
||||
private string _queueName;
|
||||
|
||||
public EventBusActiveMQ(IActiveMQPersistentConnection persistentConnection,
|
||||
ILogger<EventBusActiveMQ> logger,
|
||||
ILifetimeScope autofac,
|
||||
IEventBusSubscriptionsManager subsManager,
|
||||
IIntegrationEventSerializer serializer,
|
||||
string queueName = null,
|
||||
int retryCount = 5)
|
||||
{
|
||||
_persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
|
||||
_serializer = serializer;
|
||||
_queueName = queueName;
|
||||
_autofac = autofac;
|
||||
_retryCount = retryCount;
|
||||
_rejectedEvents = new ConcurrentQueue<Guid>();
|
||||
_consumerSession = CreateConsumerSession();
|
||||
_subsManager.OnEventRemoved += SubsManager_OnEventRemoved;
|
||||
_consumers = new List<IMessageConsumer>();
|
||||
}
|
||||
|
||||
private void SubsManager_OnEventRemoved(object sender, string eventName)
|
||||
{
|
||||
if (!_persistentConnection.IsConnected)
|
||||
{
|
||||
_persistentConnection.TryConnect();
|
||||
}
|
||||
|
||||
using (var session = _persistentConnection.CreateSession())
|
||||
{
|
||||
var messageSelector = $"eventName='{eventName}'";
|
||||
|
||||
var findedConsumer = _consumers.Find(x => x.MessageSelector == messageSelector);
|
||||
|
||||
if (findedConsumer != null)
|
||||
{
|
||||
findedConsumer.Close();
|
||||
|
||||
_consumers.Remove(findedConsumer);
|
||||
}
|
||||
|
||||
if (_subsManager.IsEmpty)
|
||||
{
|
||||
_queueName = string.Empty;
|
||||
_consumerSession.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Publish(IntegrationEvent @event)
|
||||
{
|
||||
if (!_persistentConnection.IsConnected)
|
||||
{
|
||||
_persistentConnection.TryConnect();
|
||||
}
|
||||
|
||||
var policy = Policy.Handle<SocketException>()
|
||||
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
||||
{
|
||||
_logger.WarningCouldNotPublishEvent(@event.Id, time.TotalSeconds, ex);
|
||||
});
|
||||
|
||||
using (var session = _persistentConnection.CreateSession(AcknowledgementMode.ClientAcknowledge))
|
||||
{
|
||||
var destination = session.GetQueue(_queueName);
|
||||
|
||||
using (var producer = session.CreateProducer(destination))
|
||||
{
|
||||
producer.DeliveryMode = MsgDeliveryMode.Persistent;
|
||||
|
||||
var body = _serializer.Serialize(@event);
|
||||
|
||||
var request = session.CreateStreamMessage();
|
||||
var eventName = @event.GetType().Name;
|
||||
|
||||
request.Properties["eventName"] = eventName;
|
||||
|
||||
request.WriteBytes(body);
|
||||
|
||||
producer.Send(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Subscribe<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
{
|
||||
var eventName = _subsManager.GetEventKey<T>();
|
||||
|
||||
_logger.InformationSubscribing(eventName, typeof(TH).GetGenericTypeName());
|
||||
|
||||
_subsManager.AddSubscription<T, TH>();
|
||||
|
||||
StartBasicConsume(eventName);
|
||||
}
|
||||
|
||||
public void SubscribeDynamic<TH>(string eventName) where TH : IDynamicIntegrationEventHandler
|
||||
{
|
||||
_logger.InformationSubscribingDynamic(eventName, typeof(TH).GetGenericTypeName());
|
||||
|
||||
_subsManager.AddDynamicSubscription<TH>(eventName);
|
||||
|
||||
StartBasicConsume(eventName);
|
||||
}
|
||||
|
||||
private ISession CreateConsumerSession()
|
||||
{
|
||||
if (!_persistentConnection.IsConnected)
|
||||
{
|
||||
_persistentConnection.TryConnect();
|
||||
}
|
||||
|
||||
_logger.TraceCreatingConsumerSession();
|
||||
|
||||
_consumerSession = _persistentConnection.CreateSession(AcknowledgementMode.ClientAcknowledge);
|
||||
|
||||
return _consumerSession;
|
||||
}
|
||||
|
||||
private void StartBasicConsume(string eventName)
|
||||
{
|
||||
_logger.TraceStartingBasicConsume();
|
||||
|
||||
if (!_persistentConnection.IsConnected)
|
||||
{
|
||||
_persistentConnection.TryConnect();
|
||||
}
|
||||
|
||||
var destination = _consumerSession.GetQueue(_queueName);
|
||||
|
||||
var messageSelector = $"eventName='{eventName}'";
|
||||
|
||||
var consumer = _consumerSession.CreateConsumer(destination, messageSelector);
|
||||
|
||||
_consumers.Add(consumer);
|
||||
|
||||
if (_consumerSession != null)
|
||||
{
|
||||
consumer.Listener += Consumer_Listener;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.ErrorStartBasicConsumeCantCall();
|
||||
}
|
||||
}
|
||||
|
||||
private void Consumer_Listener(IMessage objMessage)
|
||||
{
|
||||
var streamMessage = objMessage as IStreamMessage;
|
||||
|
||||
var eventName = streamMessage.Properties["eventName"].ToString();
|
||||
|
||||
var buffer = new byte[4 * 1024];
|
||||
|
||||
byte[] serializedMessage;
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
int read;
|
||||
|
||||
while ((read = streamMessage.ReadBytes(buffer)) > 0)
|
||||
{
|
||||
ms.Write(buffer, 0, read);
|
||||
|
||||
if (read < buffer.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
serializedMessage = ms.ToArray();
|
||||
}
|
||||
|
||||
var @event = GetEvent(eventName, serializedMessage);
|
||||
var message = @event.ToString();
|
||||
|
||||
try
|
||||
{
|
||||
if (message.ToLowerInvariant().Contains("throw-fake-exception"))
|
||||
{
|
||||
throw new InvalidOperationException($"Fake exception requested: \"{message}\"");
|
||||
}
|
||||
|
||||
ProcessEvent(eventName, @event)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
streamMessage.Acknowledge();
|
||||
}
|
||||
catch (IntegrationEventRejectExeption ex)
|
||||
{
|
||||
_logger.WarningProcessingMessage(message, ex);
|
||||
|
||||
if (_rejectedEvents.TryPeek(out var result) && result.Equals(ex.EventId))
|
||||
{
|
||||
_rejectedEvents.TryDequeue(out var _);
|
||||
streamMessage.Acknowledge();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rejectedEvents.Enqueue(ex.EventId);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.WarningProcessingMessage(message, ex);
|
||||
|
||||
streamMessage.Acknowledge();
|
||||
}
|
||||
}
|
||||
|
||||
private IntegrationEvent GetEvent(string eventName, byte[] serializedMessage)
|
||||
{
|
||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||
|
||||
var integrationEvent = (IntegrationEvent)_serializer.Deserialize(serializedMessage, eventType);
|
||||
|
||||
return integrationEvent;
|
||||
}
|
||||
|
||||
|
||||
public void Unsubscribe<T, TH>()
|
||||
where T : IntegrationEvent
|
||||
where TH : IIntegrationEventHandler<T>
|
||||
{
|
||||
var eventName = _subsManager.GetEventKey<T>();
|
||||
|
||||
_logger.InformationUnsubscribing(eventName);
|
||||
|
||||
_subsManager.RemoveSubscription<T, TH>();
|
||||
}
|
||||
|
||||
public void UnsubscribeDynamic<TH>(string eventName) where TH : IDynamicIntegrationEventHandler
|
||||
{
|
||||
_subsManager.RemoveDynamicSubscription<TH>(eventName);
|
||||
}
|
||||
|
||||
private void PreProcessEvent(IntegrationEvent @event)
|
||||
{
|
||||
if (_rejectedEvents.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_rejectedEvents.TryPeek(out var result) && result.Equals(@event.Id))
|
||||
{
|
||||
@event.Redelivered = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessEvent(string eventName, IntegrationEvent @event)
|
||||
{
|
||||
_logger.TraceProcessingEvent(eventName);
|
||||
|
||||
PreProcessEvent(@event);
|
||||
|
||||
if (_subsManager.HasSubscriptionsForEvent(eventName))
|
||||
{
|
||||
using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME))
|
||||
{
|
||||
var subscriptions = _subsManager.GetHandlersForEvent(eventName);
|
||||
|
||||
foreach (var subscription in subscriptions)
|
||||
{
|
||||
if (subscription.IsDynamic)
|
||||
{
|
||||
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
||||
if (handler == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using dynamic eventData = @event;
|
||||
await Task.Yield();
|
||||
await handler.Handle(eventData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var handler = scope.ResolveOptional(subscription.HandlerType);
|
||||
if (handler == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||
|
||||
await Task.Yield();
|
||||
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { @event });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.WarningNoSubscription(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var consumer in _consumers)
|
||||
{
|
||||
consumer.Dispose();
|
||||
}
|
||||
|
||||
if (_consumerSession != null)
|
||||
{
|
||||
_consumerSession.Dispose();
|
||||
}
|
||||
|
||||
_subsManager.Clear();
|
||||
}
|
||||
}
|
42
common/ASC.EventBus.ActiveMQ/GlobalUsings.cs
Normal file
42
common/ASC.EventBus.ActiveMQ/GlobalUsings.cs
Normal file
@ -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
|
||||
|
||||
global using System.Collections.Concurrent;
|
||||
global using System.Net.Sockets;
|
||||
|
||||
global using ASC.EventBus.Abstractions;
|
||||
global using ASC.EventBus.Events;
|
||||
global using ASC.EventBus.ActiveMQ.Log;
|
||||
global using Apache.NMS;
|
||||
global using Autofac;
|
||||
|
||||
global using Microsoft.Extensions.Logging;
|
||||
|
||||
global using Polly;
|
||||
|
||||
global using ASC.EventBus.Exceptions;
|
||||
global using ASC.EventBus.Extensions;
|
||||
global using ASC.EventBus.Serializers;
|
@ -0,0 +1,35 @@
|
||||
// (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.EventBus.ActiveMQ;
|
||||
|
||||
public interface IActiveMQPersistentConnection
|
||||
{
|
||||
bool IsConnected { get; }
|
||||
bool TryConnect();
|
||||
ISession CreateSession(AcknowledgementMode acknowledgementMode);
|
||||
ISession CreateSession();
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
// (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.EventBus.ActiveMQ.Log;
|
||||
internal static partial class DefaultActiveMQPersistentConnectionLogger
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Critical, Message = "DefaultActiveMQPersistentConnection")]
|
||||
public static partial void CriticalDefaultActiveMQPersistentConnection(this ILogger<DefaultActiveMQPersistentConnection> logger, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Information, Message = "ActiveMQ Client is trying to connect")]
|
||||
public static partial void InformationActiveMQTryingConnect(this ILogger<DefaultActiveMQPersistentConnection> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "ActiveMQ Client could not connect after {timeOut}s")]
|
||||
public static partial void WarningActiveMQCouldNotConnect(this ILogger<DefaultActiveMQPersistentConnection> logger, double timeOut, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Information, Message = "ActiveMQ Client acquired a persistent connection to '{hostName}' and is subscribed to failure events")]
|
||||
public static partial void InformationActiveMQAcquiredPersistentConnection(this ILogger<DefaultActiveMQPersistentConnection> logger, string hostName);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Critical, Message = "FATAL ERROR: ActiveMQ connections could not be created and opened")]
|
||||
public static partial void CriticalActiveMQCouldNotBeCreated(this ILogger<DefaultActiveMQPersistentConnection> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "A ActiveMQ connection is shutdown. Trying to re-connect...")]
|
||||
public static partial void WarningActiveMQConnectionShutdown(this ILogger<DefaultActiveMQPersistentConnection> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "A ActiveMQ connection throw exception. Trying to re-connect...")]
|
||||
public static partial void WarningActiveMQConnectionThrowException(this ILogger<DefaultActiveMQPersistentConnection> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "A ActiveMQ connection is on shutdown. Trying to re-connect...")]
|
||||
public static partial void WarningActiveMQConnectionIsOnShutDown(this ILogger<DefaultActiveMQPersistentConnection> logger);
|
||||
}
|
74
common/ASC.EventBus.ActiveMQ/Log/EventBusActiveMQLogger.cs
Normal file
74
common/ASC.EventBus.ActiveMQ/Log/EventBusActiveMQLogger.cs
Normal file
@ -0,0 +1,74 @@
|
||||
// (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.EventBus.ActiveMQ.Log;
|
||||
internal static partial class EventBusActiveMQLogger
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "Could not publish event: {eventId} after {timeout}s")]
|
||||
public static partial void WarningCouldNotPublishEvent(this ILogger<EventBusActiveMQ> logger, Guid eventId, double timeout, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Trace, Message = "Creating ActiveMQ session to publish event: {eventId} ({eventName})")]
|
||||
public static partial void TraceCreatingActiveMQSession(this ILogger<EventBusActiveMQ> logger, Guid eventId, string eventName);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Trace, Message = "Declaring ActiveMQ exchange to publish event: {eventId}")]
|
||||
public static partial void TraceDeclaringActiveMQSession(this ILogger<EventBusActiveMQ> logger, Guid eventId);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Trace, Message = "Publishing event to ActiveMQ: {eventId}")]
|
||||
public static partial void TracePublishingEvent(this ILogger<EventBusActiveMQ> logger, Guid eventId);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Information, Message = "Subscribing to dynamic event {eventName} with {eventHandler}")]
|
||||
public static partial void InformationSubscribingDynamic(this ILogger<EventBusActiveMQ> logger, string eventName, string eventHandler);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Information, Message = "Subscribing to event {eventName} with {eventHandler}")]
|
||||
public static partial void InformationSubscribing(this ILogger<EventBusActiveMQ> logger, string eventName, string eventHandler);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Information, Message = "Unsubscribing from event {eventName}")]
|
||||
public static partial void InformationUnsubscribing(this ILogger<EventBusActiveMQ> logger, string eventName);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Trace, Message = "Starting ActiveMQ basic consume")]
|
||||
public static partial void TraceStartingBasicConsume(this ILogger<EventBusActiveMQ> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Trace, Message = "Consumer tag {consumerTag} already exist. Cancelled BasicConsume again")]
|
||||
public static partial void TraceConsumerTagExist(this ILogger<EventBusActiveMQ> logger, string consumerTag);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "StartBasicConsume can't call on _consumerSession == null")]
|
||||
public static partial void ErrorStartBasicConsumeCantCall(this ILogger<EventBusActiveMQ> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "----- ERROR Processing message \"{message}\"")]
|
||||
public static partial void WarningProcessingMessage(this ILogger<EventBusActiveMQ> logger, string message, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Trace, Message = "Creating ActiveMQ consumer session")]
|
||||
public static partial void TraceCreatingConsumerSession(this ILogger<EventBusActiveMQ> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "Recreating ActiveMQ consumer session")]
|
||||
public static partial void WarningRecreatingConsumerSession(this ILogger<EventBusActiveMQ> logger, Exception exception);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Trace, Message = "Processing ActiveMQ event: {eventName}")]
|
||||
public static partial void TraceProcessingEvent(this ILogger<EventBusActiveMQ> logger, string eventName);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "No subscription for ActiveMQ event: {eventName}")]
|
||||
public static partial void WarningNoSubscription(this ILogger<EventBusActiveMQ> logger, string eventName);
|
||||
}
|
@ -65,7 +65,6 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
_subsManager.OnEventRemoved += SubsManager_OnEventRemoved;
|
||||
_serializer = serializer;
|
||||
_rejectedEvents = new ConcurrentQueue<Guid>();
|
||||
|
||||
}
|
||||
|
||||
private void SubsManager_OnEventRemoved(object sender, string eventName)
|
||||
@ -250,22 +249,16 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
|
||||
}
|
||||
catch (IntegrationEventRejectExeption ex)
|
||||
{
|
||||
_logger.WarningProcessingMessage(message, ex);
|
||||
|
||||
if (eventArgs.Redelivered)
|
||||
{
|
||||
if (_rejectedEvents.TryPeek(out var result) && result.Equals(ex.EventId))
|
||||
{
|
||||
_rejectedEvents.TryDequeue(out var _);
|
||||
_consumerChannel.BasicReject(eventArgs.DeliveryTag, requeue: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rejectedEvents.Enqueue(ex.EventId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.WarningProcessingMessage(message, ex);
|
||||
|
||||
if (_rejectedEvents.TryPeek(out var result) && result.Equals(ex.EventId))
|
||||
{
|
||||
_rejectedEvents.TryDequeue(out var _);
|
||||
_consumerChannel.BasicReject(eventArgs.DeliveryTag, requeue: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rejectedEvents.Enqueue(ex.EventId);
|
||||
_consumerChannel.BasicNack(eventArgs.DeliveryTag, multiple: false, requeue: true);
|
||||
}
|
||||
}
|
||||
|
5
config/activemq.json
Normal file
5
config/activemq.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"ActiveMQ": {
|
||||
"Uri": "amqp://127.0.0.1:5672"
|
||||
}
|
||||
}
|
@ -385,10 +385,7 @@ const ConnectDialog = withTranslation([
|
||||
])(PureConnectDialogContainer);
|
||||
|
||||
export default inject(
|
||||
(
|
||||
{ auth, settingsStore, selectedFolderStore, dialogsStore },
|
||||
{ passedItem, isConnectionViaBackupModule }
|
||||
) => {
|
||||
({ auth, settingsStore, selectedFolderStore, dialogsStore, backup }) => {
|
||||
const {
|
||||
providers,
|
||||
saveThirdParty,
|
||||
@ -398,6 +395,7 @@ export default inject(
|
||||
const { personal, folderFormValidation } = auth.settingsStore;
|
||||
|
||||
const { id, folders } = selectedFolderStore;
|
||||
const { selectedThirdPartyAccount: backupConnectionItem } = backup;
|
||||
const {
|
||||
connectDialogVisible: visible,
|
||||
setConnectDialogVisible,
|
||||
@ -410,7 +408,8 @@ export default inject(
|
||||
setSaveAfterReconnectOAuth,
|
||||
} = dialogsStore;
|
||||
|
||||
const item = isConnectionViaBackupModule ? passedItem : connectItem;
|
||||
const item = backupConnectionItem ?? connectItem;
|
||||
const isConnectionViaBackupModule = backupConnectionItem ? true : false;
|
||||
|
||||
return {
|
||||
selectedFolderId: id,
|
||||
@ -421,7 +420,7 @@ export default inject(
|
||||
roomCreation,
|
||||
setSaveThirdpartyResponse,
|
||||
folderFormValidation,
|
||||
|
||||
isConnectionViaBackupModule,
|
||||
saveThirdParty,
|
||||
openConnectWindow,
|
||||
fetchThirdPartyProviders,
|
||||
|
@ -97,24 +97,27 @@ const DeleteThirdPartyDialog = (props) => {
|
||||
};
|
||||
|
||||
export default inject(
|
||||
(
|
||||
{ filesStore, settingsStore, dialogsStore, selectedFolderStore },
|
||||
{ item, isConnectionViaBackupModule }
|
||||
) => {
|
||||
({
|
||||
filesStore,
|
||||
settingsStore,
|
||||
dialogsStore,
|
||||
selectedFolderStore,
|
||||
backup,
|
||||
}) => {
|
||||
const {
|
||||
providers,
|
||||
setThirdPartyProviders,
|
||||
deleteThirdParty,
|
||||
} = settingsStore.thirdPartyStore;
|
||||
const { fetchFiles } = filesStore;
|
||||
|
||||
const { selectedThirdPartyAccount: backupConnectionItem } = backup;
|
||||
const {
|
||||
deleteThirdPartyDialogVisible: visible,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
removeItem: storeItem,
|
||||
} = dialogsStore;
|
||||
|
||||
const removeItem = isConnectionViaBackupModule ? item : storeItem;
|
||||
const removeItem = backupConnectionItem ?? storeItem;
|
||||
|
||||
return {
|
||||
currentFolderId: selectedFolderStore.id,
|
||||
|
@ -79,10 +79,15 @@ class FilesListWrapper extends React.Component {
|
||||
if (axios.isCancel(thrown)) {
|
||||
console.log("Request canceled", thrown.message);
|
||||
} else {
|
||||
console.error(thrown);
|
||||
const errorBody = thrown.response;
|
||||
|
||||
if (errorBody.data && errorBody.data.error) {
|
||||
toastr.error(errorBody.data.error.message);
|
||||
}
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
if (!response) return;
|
||||
const data = response.data.response;
|
||||
|
||||
|
@ -23,6 +23,8 @@ import withPeopleLoader from "SRC_DIR/HOCs/withPeopleLoader";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
min-height: 33px;
|
||||
height: 60px;
|
||||
|
||||
.group-button-menu-container {
|
||||
margin: 0 0 0 -20px;
|
||||
@ -142,6 +144,7 @@ const StyledInfoPanelToggleWrapper = styled.div`
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -11,7 +11,7 @@ const CommentEditor = ({
|
||||
item,
|
||||
|
||||
setSelection,
|
||||
|
||||
isRecycleBinFolder,
|
||||
fetchFileVersions,
|
||||
updateCommentVersion,
|
||||
}) => {
|
||||
@ -60,15 +60,17 @@ const CommentEditor = ({
|
||||
{comment}
|
||||
</Text>
|
||||
)}
|
||||
<div className="edit_toggle" onClick={onOpenEditor}>
|
||||
<ReactSVG
|
||||
className="edit_toggle-icon"
|
||||
src="images/pencil.react.svg"
|
||||
/>
|
||||
<div className="property-content edit_toggle-text">
|
||||
{comment ? t("Common:EditButton") : t("Common:AddButton")}
|
||||
{!isRecycleBinFolder && (
|
||||
<div className="edit_toggle" onClick={onOpenEditor}>
|
||||
<ReactSVG
|
||||
className="edit_toggle-icon"
|
||||
src="images/pencil.react.svg"
|
||||
/>
|
||||
<div className="property-content edit_toggle-text">
|
||||
{comment ? t("Common:EditButton") : t("Common:AddButton")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="property-comment_editor-editor">
|
||||
@ -101,14 +103,14 @@ const CommentEditor = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth, versionHistoryStore }) => {
|
||||
export default inject(({ auth, versionHistoryStore, treeFoldersStore }) => {
|
||||
const { setSelection } = auth.infoPanelStore;
|
||||
|
||||
const { fetchFileVersions, updateCommentVersion } = versionHistoryStore;
|
||||
|
||||
const { isRecycleBinFolder } = treeFoldersStore;
|
||||
return {
|
||||
setSelection,
|
||||
|
||||
isRecycleBinFolder,
|
||||
fetchFileVersions,
|
||||
updateCommentVersion,
|
||||
};
|
||||
|
@ -60,6 +60,7 @@ const StyledContainer = styled.div`
|
||||
|
||||
.header-container {
|
||||
min-height: 33px;
|
||||
height: 60px;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -303,7 +304,7 @@ class SectionHeaderContent extends React.Component {
|
||||
};
|
||||
|
||||
getContextOptionsFolder = () => {
|
||||
const { t, toggleInfoPanel, personal } = this.props;
|
||||
const { t, isRecycleBinFolder } = this.props;
|
||||
|
||||
return [
|
||||
{
|
||||
@ -493,7 +494,6 @@ class SectionHeaderContent extends React.Component {
|
||||
isHeaderChecked,
|
||||
isHeaderIndeterminate,
|
||||
showText,
|
||||
toggleInfoPanel,
|
||||
isRoomsFolder,
|
||||
isEmptyPage,
|
||||
} = this.props;
|
||||
|
@ -449,7 +449,6 @@ const WhiteLabel = (props) => {
|
||||
fontWeight="600"
|
||||
isHovered
|
||||
type="action"
|
||||
color={!isPortalPaid ? "#A3A9AE" : ""}
|
||||
className="settings_unavailable"
|
||||
>
|
||||
{t("ChangeLogoButton")}
|
||||
@ -505,7 +504,6 @@ const WhiteLabel = (props) => {
|
||||
fontWeight="600"
|
||||
isHovered
|
||||
type="action"
|
||||
color={!isPortalPaid ? "#A3A9AE" : ""}
|
||||
className="settings_unavailable"
|
||||
>
|
||||
{t("ChangeLogoButton")}
|
||||
@ -561,7 +559,6 @@ const WhiteLabel = (props) => {
|
||||
fontWeight="600"
|
||||
isHovered
|
||||
type="action"
|
||||
color={!isPortalPaid ? "#A3A9AE" : ""}
|
||||
className="settings_unavailable"
|
||||
>
|
||||
{t("ChangeLogoButton")}
|
||||
@ -617,7 +614,6 @@ const WhiteLabel = (props) => {
|
||||
fontWeight="600"
|
||||
isHovered
|
||||
type="action"
|
||||
color={!isPortalPaid ? "#A3A9AE" : ""}
|
||||
className="settings_unavailable"
|
||||
>
|
||||
{t("ChangeLogoButton")}
|
||||
@ -674,7 +670,6 @@ const WhiteLabel = (props) => {
|
||||
fontWeight="600"
|
||||
isHovered
|
||||
type="action"
|
||||
color={!isPortalPaid ? "#A3A9AE" : ""}
|
||||
className="settings_unavailable"
|
||||
>
|
||||
{t("ChangeLogoButton")}
|
||||
@ -779,7 +774,6 @@ const WhiteLabel = (props) => {
|
||||
fontWeight="600"
|
||||
isHovered
|
||||
type="action"
|
||||
color={!isPortalPaid ? "#A3A9AE" : ""}
|
||||
className="settings_unavailable"
|
||||
>
|
||||
{t("ChangeLogoButton")}
|
||||
@ -836,7 +830,6 @@ const WhiteLabel = (props) => {
|
||||
fontWeight="600"
|
||||
isHovered
|
||||
type="action"
|
||||
color={!isPortalPaid ? "#A3A9AE" : ""}
|
||||
className="settings_unavailable"
|
||||
>
|
||||
{t("ChangeLogoButton")}
|
||||
|
@ -64,6 +64,7 @@ const commonStyles = css`
|
||||
max-width: ${TEXT_LENGTH};
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
`;
|
||||
|
||||
@ -230,7 +231,7 @@ const StyledModules = styled.div`
|
||||
margin-bottom: 24px;
|
||||
.backup-description {
|
||||
${(props) => props.isDisabled && `color: #A3A9AE`};
|
||||
margin-left: 24px;
|
||||
margin-left: 29px;
|
||||
max-width: 700px;
|
||||
}
|
||||
`;
|
||||
@ -325,10 +326,18 @@ const StyledBackup = styled.div`
|
||||
.backup_connection {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(100px, 310px) 32px;
|
||||
grid-gap: 8px;
|
||||
}
|
||||
.backup_third-party-combo {
|
||||
max-width: 310px;
|
||||
margin-right: 8px;
|
||||
.combo-button {
|
||||
justify-content: flex-start;
|
||||
.combo-button-label {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.backup_modules-separation {
|
||||
@ -363,6 +372,9 @@ const StyledBackup = styled.div`
|
||||
}
|
||||
}
|
||||
}
|
||||
.backup_third-party-context {
|
||||
margin-top: 4px;
|
||||
}
|
||||
`;
|
||||
const StyledBackupList = styled.div`
|
||||
height: 100%;
|
||||
|
@ -64,6 +64,7 @@ const ScheduleComponent = ({
|
||||
scaledOptions={true}
|
||||
dropDownMaxHeight={500}
|
||||
className="schedule-backup_combobox days_option"
|
||||
showDisabledItems
|
||||
/>
|
||||
{weeklySchedule && (
|
||||
<ComboBox
|
||||
@ -79,6 +80,7 @@ const ScheduleComponent = ({
|
||||
scaledOptions={true}
|
||||
dropDownMaxHeight={400}
|
||||
className="schedule-backup_combobox weekly_option"
|
||||
showDisabledItems
|
||||
/>
|
||||
)}
|
||||
{monthlySchedule && (
|
||||
@ -95,6 +97,7 @@ const ScheduleComponent = ({
|
||||
scaledOptions={true}
|
||||
dropDownMaxHeight={400}
|
||||
className="schedule-backup_combobox month_options"
|
||||
showDisabledItems
|
||||
/>
|
||||
)}
|
||||
<ComboBox
|
||||
@ -110,6 +113,7 @@ const ScheduleComponent = ({
|
||||
scaledOptions={true}
|
||||
dropDownMaxHeight={isMobileOnly ? 100 : 200}
|
||||
className="schedule-backup_combobox time_options"
|
||||
showDisabledItems
|
||||
/>
|
||||
</div>
|
||||
<div className="maxCopiesOption">
|
||||
@ -128,6 +132,7 @@ const ScheduleComponent = ({
|
||||
scaledOptions={true}
|
||||
dropDownMaxHeight={isMobileOnly ? 100 : 200}
|
||||
className="schedule-backup_combobox max_copies"
|
||||
showDisabledItems
|
||||
/>
|
||||
</div>
|
||||
</StyledScheduleComponent>
|
||||
|
@ -70,6 +70,7 @@ class ThirdPartyStorageModule extends React.PureComponent {
|
||||
scaledOptions
|
||||
dropDownMaxHeight={300}
|
||||
className="backup_combo"
|
||||
showDisabledItems
|
||||
/>
|
||||
|
||||
{selectedStorageId === GoogleId && (
|
||||
|
@ -16,6 +16,7 @@ import ConnectDialog from "../../../../../../components/dialogs/ConnectDialog";
|
||||
import { ContextMenuButton } from "@docspace/components";
|
||||
import DeleteThirdPartyDialog from "../../../../../../components/dialogs/DeleteThirdPartyDialog";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { getOAuthToken } from "@docspace/common/utils";
|
||||
|
||||
let accounts = [],
|
||||
connectedAccount,
|
||||
@ -23,7 +24,6 @@ let accounts = [],
|
||||
const DirectThirdPartyConnection = (props) => {
|
||||
const {
|
||||
openConnectWindow,
|
||||
getOAuthToken,
|
||||
t,
|
||||
onSelectFolder,
|
||||
onClose,
|
||||
@ -42,14 +42,21 @@ const DirectThirdPartyConnection = (props) => {
|
||||
deleteThirdPartyDialogVisible,
|
||||
tReady,
|
||||
clearLocalStorage,
|
||||
setSelectedThirdPartyAccount,
|
||||
selectedThirdPartyAccount,
|
||||
} = props;
|
||||
|
||||
useEffect(() => {
|
||||
tReady && updateAccountsInfo(true);
|
||||
}, [tReady]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setSelectedThirdPartyAccount(null);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const initialState = {
|
||||
selectedAccount: {},
|
||||
folderList: [],
|
||||
isLoading: false,
|
||||
isInitialLoading: true,
|
||||
@ -149,14 +156,17 @@ const DirectThirdPartyConnection = (props) => {
|
||||
setAccount("Yandex", t("Translations:TypeTitleYandex"));
|
||||
setAccount("WebDav", t("Translations:TypeTitleWebDav"));
|
||||
|
||||
setSelectedThirdPartyAccount(
|
||||
Object.keys(selectedAccount).length !== 0
|
||||
? selectedAccount
|
||||
: { ...accounts[0] }
|
||||
);
|
||||
|
||||
setState({
|
||||
isLoading: false,
|
||||
isUpdatingInfo: false,
|
||||
isInitialLoading: false,
|
||||
selectedAccount:
|
||||
Object.keys(selectedAccount).length !== 0
|
||||
? selectedAccount
|
||||
: { ...accounts[0] },
|
||||
|
||||
folderList: account ? account : [],
|
||||
});
|
||||
} catch (e) {
|
||||
@ -172,7 +182,7 @@ const DirectThirdPartyConnection = (props) => {
|
||||
|
||||
const onConnect = () => {
|
||||
clearLocalStorage();
|
||||
const { provider_link, provider_key } = state.selectedAccount;
|
||||
const { provider_link, provider_key } = selectedThirdPartyAccount;
|
||||
|
||||
const directConnection = provider_link;
|
||||
|
||||
@ -184,10 +194,10 @@ const DirectThirdPartyConnection = (props) => {
|
||||
);
|
||||
|
||||
openConnectWindow(provider_key, authModal)
|
||||
.then(getOAuthToken)
|
||||
.then((modal) => getOAuthToken(modal))
|
||||
.then((token) => {
|
||||
saveSettings(token);
|
||||
authModal.close();
|
||||
saveSettings(token);
|
||||
})
|
||||
.catch((e) => {
|
||||
if (!e) return;
|
||||
@ -209,7 +219,7 @@ const DirectThirdPartyConnection = (props) => {
|
||||
loginValue = "",
|
||||
passwordValue = ""
|
||||
) => {
|
||||
const { label, provider_key, provider_id } = state.selectedAccount;
|
||||
const { label, provider_key, provider_id } = selectedThirdPartyAccount;
|
||||
setState({ isLoading: true, isUpdatingInfo: true });
|
||||
connectDialogVisible && setConnectDialogVisible(false);
|
||||
onSelectFolder && onSelectFolder("");
|
||||
@ -235,14 +245,13 @@ const DirectThirdPartyConnection = (props) => {
|
||||
|
||||
const onSelectAccount = (options) => {
|
||||
const key = options.key;
|
||||
|
||||
setState({ selectedAccount: { ...accounts[+key] } });
|
||||
setSelectedThirdPartyAccount({ ...accounts[+key] });
|
||||
};
|
||||
|
||||
const onReconnect = () => {
|
||||
clearLocalStorage();
|
||||
|
||||
const { provider_link } = state.selectedAccount;
|
||||
const { provider_link } = selectedThirdPartyAccount;
|
||||
|
||||
const directConnection = provider_link;
|
||||
|
||||
@ -252,12 +261,12 @@ const DirectThirdPartyConnection = (props) => {
|
||||
"Authorization",
|
||||
"height=600, width=1020"
|
||||
);
|
||||
openConnectWindow(selectedAccount.provider_key, authModal).then((modal) =>
|
||||
getOAuthToken(modal).then((token) => {
|
||||
openConnectWindow(selectedThirdPartyAccount.provider_key, authModal)
|
||||
.then((modal) => getOAuthToken(modal))
|
||||
.then((token) => {
|
||||
authModal.close();
|
||||
saveSettings(token);
|
||||
})
|
||||
);
|
||||
});
|
||||
} else {
|
||||
setConnectDialogVisible(true);
|
||||
}
|
||||
@ -271,10 +280,10 @@ const DirectThirdPartyConnection = (props) => {
|
||||
return [
|
||||
{
|
||||
key: "connection-settings",
|
||||
label: selectedAccount.connected
|
||||
label: selectedThirdPartyAccount.connected
|
||||
? t("Common:Reconnect")
|
||||
: t("Common:Connect"),
|
||||
onClick: selectedAccount.connected ? onReconnect : onConnect,
|
||||
onClick: selectedThirdPartyAccount.connected ? onReconnect : onConnect,
|
||||
disabled: false,
|
||||
icon: "/static/images/refresh.react.svg",
|
||||
},
|
||||
@ -282,19 +291,13 @@ const DirectThirdPartyConnection = (props) => {
|
||||
key: "Disconnect-settings",
|
||||
label: t("Common:Disconnect"),
|
||||
onClick: onDisconnect,
|
||||
disabled: selectedAccount.connected ? false : true,
|
||||
disabled: selectedThirdPartyAccount.connected ? false : true,
|
||||
icon: "/static/images/access.none.react.svg",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const {
|
||||
selectedAccount,
|
||||
isLoading,
|
||||
folderList,
|
||||
isInitialLoading,
|
||||
isUpdatingInfo,
|
||||
} = state;
|
||||
const { isLoading, folderList, isInitialLoading, isUpdatingInfo } = state;
|
||||
|
||||
return (
|
||||
<StyledBackup>
|
||||
@ -304,13 +307,14 @@ const DirectThirdPartyConnection = (props) => {
|
||||
options={accounts}
|
||||
selectedOption={{
|
||||
key: 0,
|
||||
label: selectedAccount?.label,
|
||||
label: selectedThirdPartyAccount?.label,
|
||||
}}
|
||||
onSelect={onSelectAccount}
|
||||
noBorder={false}
|
||||
scaledOptions
|
||||
dropDownMaxHeight={300}
|
||||
tabIndex={1}
|
||||
showDisabledItems
|
||||
isDisabled={
|
||||
!tReady ||
|
||||
isDisabled ||
|
||||
@ -374,19 +378,10 @@ const DirectThirdPartyConnection = (props) => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{connectDialogVisible && (
|
||||
<ConnectDialog
|
||||
passedItem={selectedAccount}
|
||||
updateInfo={updateAccountsInfo}
|
||||
isConnectionViaBackupModule
|
||||
/>
|
||||
)}
|
||||
|
||||
{deleteThirdPartyDialogVisible && (
|
||||
<DeleteThirdPartyDialog
|
||||
updateInfo={updateAccountsInfo}
|
||||
key="thirdparty-delete-dialog"
|
||||
item={selectedAccount}
|
||||
isConnectionViaBackupModule
|
||||
/>
|
||||
)}
|
||||
@ -395,9 +390,14 @@ const DirectThirdPartyConnection = (props) => {
|
||||
};
|
||||
|
||||
export default inject(({ auth, backup, dialogsStore, settingsStore }) => {
|
||||
const { commonThirdPartyList, clearLocalStorage } = backup;
|
||||
const {
|
||||
commonThirdPartyList,
|
||||
clearLocalStorage,
|
||||
setSelectedThirdPartyAccount,
|
||||
selectedThirdPartyAccount,
|
||||
} = backup;
|
||||
const { openConnectWindow } = settingsStore.thirdPartyStore;
|
||||
const { getOAuthToken } = auth.settingsStore;
|
||||
|
||||
const {
|
||||
connectDialogVisible,
|
||||
setConnectDialogVisible,
|
||||
@ -409,11 +409,12 @@ export default inject(({ auth, backup, dialogsStore, settingsStore }) => {
|
||||
clearLocalStorage,
|
||||
commonThirdPartyList,
|
||||
openConnectWindow,
|
||||
getOAuthToken,
|
||||
setConnectDialogVisible,
|
||||
connectDialogVisible,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
deleteThirdPartyDialogVisible,
|
||||
setSelectedThirdPartyAccount,
|
||||
selectedThirdPartyAccount,
|
||||
};
|
||||
})(
|
||||
withTranslation(["Settings", "Common", "Translations"])(
|
||||
|
@ -21,7 +21,7 @@ class ThirdPartyStorageModule extends React.PureComponent {
|
||||
|
||||
storageTitle = getFromLocalStorage("LocalCopyThirdPartyStorageType");
|
||||
storageId = getFromLocalStorage("LocalCopyStorage");
|
||||
console.log("storageId", storageId);
|
||||
|
||||
this.state = {
|
||||
comboBoxOptions: [],
|
||||
storagesInfo: {},
|
||||
@ -122,6 +122,7 @@ class ThirdPartyStorageModule extends React.PureComponent {
|
||||
scaledOptions
|
||||
dropDownMaxHeight={400}
|
||||
className="backup_combo"
|
||||
showDisabledItems
|
||||
/>
|
||||
|
||||
{selectedId === GoogleId && <GoogleCloudStorage {...commonProps} />}
|
||||
|
@ -82,6 +82,7 @@ class ThirdPartyStoragesModule extends React.PureComponent {
|
||||
scaledOptions
|
||||
dropDownMaxHeight={400}
|
||||
className="backup_combo"
|
||||
showDisabledItems
|
||||
/>
|
||||
|
||||
{selectedStorageId === GoogleId && (
|
||||
|
@ -63,6 +63,7 @@ class BackupStore {
|
||||
defaultEnableSchedule = false;
|
||||
|
||||
storageRegions = [];
|
||||
selectedThirdPartyAccount = null;
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
@ -143,6 +144,11 @@ class BackupStore {
|
||||
return false;
|
||||
}
|
||||
|
||||
setSelectedThirdPartyAccount = (elem) => {
|
||||
this.selectedThirdPartyAccount = elem;
|
||||
|
||||
};
|
||||
|
||||
toDefault = () => {
|
||||
this.selectedMonthlySchedule = this.defaultMonthlySchedule;
|
||||
this.selectedWeeklySchedule = this.defaultWeeklySchedule;
|
||||
|
@ -6,6 +6,7 @@ $font-family-base: "Open Sans", sans-serif;
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
#root {
|
||||
min-height: 100%;
|
||||
|
@ -10,14 +10,19 @@ const StyledOuter = styled.div`
|
||||
${(props) =>
|
||||
props.isNeedBorder &&
|
||||
css`
|
||||
border: ${(props) => props.theme.client.settings.backup.contextBorder};
|
||||
border: ${(props) => props.theme.comboBox.button.border};
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
|
||||
svg {
|
||||
padding: 7px 13px 7px 2px;
|
||||
}
|
||||
:hover {
|
||||
border-color: ${(props) =>
|
||||
props.theme.comboBox.button.hoverBorderColor};
|
||||
}
|
||||
`}
|
||||
`;
|
||||
StyledOuter.defaultProps = { theme: Base };
|
||||
|
@ -2893,7 +2893,6 @@ const Base = {
|
||||
backup: {
|
||||
rectangleBackgroundColor: "#f8f9f9",
|
||||
separatorBorder: "1px solid #eceef1",
|
||||
contextBorder: "1px solid #D0D5DA",
|
||||
},
|
||||
|
||||
payment: {
|
||||
|
@ -2900,7 +2900,6 @@ const Dark = {
|
||||
backup: {
|
||||
rectangleBackgroundColor: "#292929",
|
||||
separatorBorder: "1px solid #474747",
|
||||
contextBorder: "1px solid #D0D5DA",
|
||||
},
|
||||
|
||||
payment: {
|
||||
|
@ -509,16 +509,6 @@ public class FileSecurity : IFileSecurity
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isVisitor && e.RootFolderType == FolderType.Recent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isVisitor && e.RootFolderType == FolderType.Favorites)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isVisitor && e.RootFolderType == FolderType.Templates)
|
||||
{
|
||||
return false;
|
||||
|
@ -379,6 +379,11 @@ public class GlobalFolder
|
||||
return default;
|
||||
}
|
||||
|
||||
if (_userManager.IsVisitor(_authContext.CurrentAccount.ID))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var key = $"archive/{_tenantManager.GetCurrentTenant().Id}";
|
||||
|
||||
if (!DocSpaceFolderCache.TryGetValue(key, out var result))
|
||||
@ -517,11 +522,6 @@ public class GlobalFolder
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_userManager.IsVisitor(_authContext.CurrentAccount.ID))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!RecentFolderCache.TryGetValue(_tenantManager.GetCurrentTenant().Id, out var recentFolderId))
|
||||
{
|
||||
var folderDao = daoFactory.GetFolderDao<int>();
|
||||
@ -546,11 +546,6 @@ public class GlobalFolder
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_userManager.IsVisitor(_authContext.CurrentAccount.ID))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!FavoritesFolderCache.TryGetValue(_tenantManager.GetCurrentTenant().Id, out var favoriteFolderId))
|
||||
{
|
||||
var folderDao = daoFactory.GetFolderDao<int>();
|
||||
|
@ -114,7 +114,7 @@ public class FoldersControllerHelper<T> : FilesHelperBase<T>
|
||||
yield return await _globalFolderHelper.FolderShareAsync;
|
||||
}
|
||||
|
||||
if (!IsVisitor && !withoutAdditionalFolder)
|
||||
if (!withoutAdditionalFolder)
|
||||
{
|
||||
if (_filesSettingsHelper.FavoritesSection)
|
||||
{
|
||||
@ -126,8 +126,10 @@ public class FoldersControllerHelper<T> : FilesHelperBase<T>
|
||||
yield return await _globalFolderHelper.FolderRecentAsync;
|
||||
}
|
||||
|
||||
if (!_coreBaseSettings.Personal && _coreBaseSettings.DisableDocSpace
|
||||
&& PrivacyRoomSettings.IsAvailable())
|
||||
if (!IsVisitor &&
|
||||
!_coreBaseSettings.Personal &&
|
||||
_coreBaseSettings.DisableDocSpace &&
|
||||
PrivacyRoomSettings.IsAvailable())
|
||||
{
|
||||
yield return await _globalFolderHelper.FolderPrivacyAsync;
|
||||
}
|
||||
@ -147,15 +149,19 @@ public class FoldersControllerHelper<T> : FilesHelperBase<T>
|
||||
yield return await _globalFolderHelper.FolderTemplatesAsync;
|
||||
}
|
||||
|
||||
if (!withoutTrash)
|
||||
if (!withoutTrash && !IsVisitor)
|
||||
{
|
||||
yield return (int)_globalFolderHelper.FolderTrash;
|
||||
}
|
||||
|
||||
if (!_coreBaseSettings.DisableDocSpace)
|
||||
{
|
||||
yield return await _globalFolderHelper.FolderVirtualRoomsAsync;
|
||||
yield return await _globalFolderHelper.FolderArchiveAsync;
|
||||
yield return await _globalFolderHelper.FolderVirtualRoomsAsync;
|
||||
|
||||
if (!IsVisitor)
|
||||
{
|
||||
yield return await _globalFolderHelper.FolderArchiveAsync;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,6 @@ public class UserController : PeopleControllerBase
|
||||
|
||||
private readonly ICache _cache;
|
||||
private readonly TenantManager _tenantManager;
|
||||
private readonly GlobalSpace _globalSpace;
|
||||
private readonly Constants _constants;
|
||||
private readonly CookiesManager _cookiesManager;
|
||||
private readonly CoreBaseSettings _coreBaseSettings;
|
||||
private readonly CustomNamingPeople _customNamingPeople;
|
||||
@ -69,8 +67,6 @@ public class UserController : PeopleControllerBase
|
||||
public UserController(
|
||||
ICache cache,
|
||||
TenantManager tenantManager,
|
||||
GlobalSpace globalSpace,
|
||||
Constants constants,
|
||||
CookiesManager cookiesManager,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CustomNamingPeople customNamingPeople,
|
||||
@ -112,8 +108,6 @@ public class UserController : PeopleControllerBase
|
||||
{
|
||||
_cache = cache;
|
||||
_tenantManager = tenantManager;
|
||||
_globalSpace = globalSpace;
|
||||
_constants = constants;
|
||||
_cookiesManager = cookiesManager;
|
||||
_coreBaseSettings = coreBaseSettings;
|
||||
_customNamingPeople = customNamingPeople;
|
||||
|
@ -301,7 +301,7 @@ public class AuthenticationController : ControllerBase
|
||||
_securityContext.Logout();
|
||||
}
|
||||
|
||||
[AllowNotPayment]
|
||||
[AllowNotPayment, AllowSuspended]
|
||||
[HttpPost("confirm")]
|
||||
public ValidationResult CheckConfirm(EmailValidationKeyModel inDto)
|
||||
{
|
||||
|
@ -444,7 +444,7 @@ public class PortalController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpDelete("delete")]
|
||||
[Authorize(AuthenticationSchemes = "confirm", Roles = "ProfileRemove")]
|
||||
[Authorize(AuthenticationSchemes = "confirm", Roles = "PortalRemove")]
|
||||
public async Task<object> DeletePortal()
|
||||
{
|
||||
_tenantManager.RemoveTenant(Tenant.Id);
|
||||
|
@ -132,8 +132,7 @@ public class SettingsController : BaseSettingsController
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
[AllowNotPayment]
|
||||
[AllowAnonymous]
|
||||
[AllowNotPayment, AllowSuspended, AllowAnonymous]
|
||||
public SettingsDto GetSettings(bool? withpassword)
|
||||
{
|
||||
var studioAdminMessageSettings = _settingsManager.Load<StudioAdminMessageSettings>();
|
||||
|
@ -209,7 +209,7 @@ public class WhitelabelController : BaseSettingsController
|
||||
|
||||
result.Add(instance);
|
||||
|
||||
if (!instance.IsDefault() && !instance.IsLicensor)
|
||||
if (!instance.IsDefault && !instance.IsLicensor)
|
||||
{
|
||||
result.Add(_settingsManager.GetDefault<CompanyWhiteLabelSettings>());
|
||||
}
|
||||
@ -280,8 +280,6 @@ public class WhitelabelController : BaseSettingsController
|
||||
[HttpGet("rebranding/additional")]
|
||||
public AdditionalWhiteLabelSettings GetAdditionalWhiteLabelSettings()
|
||||
{
|
||||
_permissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||
|
||||
return _settingsManager.Load<AdditionalWhiteLabelSettings>();
|
||||
}
|
||||
|
||||
|
@ -60,22 +60,25 @@ public class AdditionalWhiteLabelSettings : ISettings<AdditionalWhiteLabelSettin
|
||||
|
||||
public string LicenseAgreementsUrl { get; set; }
|
||||
|
||||
public bool IsDefault()
|
||||
public bool IsDefault
|
||||
{
|
||||
var defaultSettings = GetDefault();
|
||||
|
||||
return StartDocsEnabled == defaultSettings.StartDocsEnabled &&
|
||||
HelpCenterEnabled == defaultSettings.HelpCenterEnabled &&
|
||||
FeedbackAndSupportEnabled == defaultSettings.FeedbackAndSupportEnabled &&
|
||||
FeedbackAndSupportUrl == defaultSettings.FeedbackAndSupportUrl &&
|
||||
UserForumEnabled == defaultSettings.UserForumEnabled &&
|
||||
UserForumUrl == defaultSettings.UserForumUrl &&
|
||||
VideoGuidesEnabled == defaultSettings.VideoGuidesEnabled &&
|
||||
VideoGuidesUrl == defaultSettings.VideoGuidesUrl &&
|
||||
SalesEmail == defaultSettings.SalesEmail &&
|
||||
BuyUrl == defaultSettings.BuyUrl &&
|
||||
LicenseAgreementsEnabled == defaultSettings.LicenseAgreementsEnabled &&
|
||||
LicenseAgreementsUrl == defaultSettings.LicenseAgreementsUrl;
|
||||
get
|
||||
{
|
||||
var defaultSettings = GetDefault();
|
||||
|
||||
return StartDocsEnabled == defaultSettings.StartDocsEnabled &&
|
||||
HelpCenterEnabled == defaultSettings.HelpCenterEnabled &&
|
||||
FeedbackAndSupportEnabled == defaultSettings.FeedbackAndSupportEnabled &&
|
||||
FeedbackAndSupportUrl == defaultSettings.FeedbackAndSupportUrl &&
|
||||
UserForumEnabled == defaultSettings.UserForumEnabled &&
|
||||
UserForumUrl == defaultSettings.UserForumUrl &&
|
||||
VideoGuidesEnabled == defaultSettings.VideoGuidesEnabled &&
|
||||
VideoGuidesUrl == defaultSettings.VideoGuidesUrl &&
|
||||
SalesEmail == defaultSettings.SalesEmail &&
|
||||
BuyUrl == defaultSettings.BuyUrl &&
|
||||
LicenseAgreementsEnabled == defaultSettings.LicenseAgreementsEnabled &&
|
||||
LicenseAgreementsUrl == defaultSettings.LicenseAgreementsUrl;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
|
@ -34,7 +34,7 @@ public class CompanyWhiteLabelSettingsWrapper
|
||||
[Serializable]
|
||||
public class CompanyWhiteLabelSettings : ISettings<CompanyWhiteLabelSettings>
|
||||
{
|
||||
private readonly CoreSettings _coreSettings;
|
||||
private CoreSettings _coreSettings;
|
||||
|
||||
public string CompanyName { get; set; }
|
||||
|
||||
@ -59,16 +59,19 @@ public class CompanyWhiteLabelSettings : ISettings<CompanyWhiteLabelSettings>
|
||||
|
||||
}
|
||||
|
||||
public bool IsDefault()
|
||||
public bool IsDefault
|
||||
{
|
||||
var defaultSettings = GetDefault();
|
||||
|
||||
return CompanyName == defaultSettings.CompanyName &&
|
||||
Site == defaultSettings.Site &&
|
||||
Email == defaultSettings.Email &&
|
||||
Address == defaultSettings.Address &&
|
||||
Phone == defaultSettings.Phone &&
|
||||
IsLicensor == defaultSettings.IsLicensor;
|
||||
get
|
||||
{
|
||||
var defaultSettings = GetDefault();
|
||||
|
||||
return CompanyName == defaultSettings.CompanyName &&
|
||||
Site == defaultSettings.Site &&
|
||||
Email == defaultSettings.Email &&
|
||||
Address == defaultSettings.Address &&
|
||||
Phone == defaultSettings.Phone &&
|
||||
IsLicensor == defaultSettings.IsLicensor;
|
||||
}
|
||||
}
|
||||
|
||||
#region ISettings Members
|
||||
@ -84,7 +87,11 @@ public class CompanyWhiteLabelSettings : ISettings<CompanyWhiteLabelSettings>
|
||||
{
|
||||
var settings = _coreSettings.GetSetting("CompanyWhiteLabelSettings");
|
||||
|
||||
return string.IsNullOrEmpty(settings) ? new CompanyWhiteLabelSettings(_coreSettings) : JsonConvert.DeserializeObject<CompanyWhiteLabelSettings>(settings);
|
||||
var result = string.IsNullOrEmpty(settings) ? new CompanyWhiteLabelSettings(_coreSettings) : JsonConvert.DeserializeObject<CompanyWhiteLabelSettings>(settings);
|
||||
|
||||
result._coreSettings = _coreSettings;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
Loading…
Reference in New Issue
Block a user