Merge branch 'hotfix/v1.0.1' into bugfix/62456

This commit is contained in:
pavelbannov 2023-05-08 17:26:43 +03:00
commit aa13ea9013
18 changed files with 443 additions and 463 deletions

View File

@ -24,10 +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.Linq;
using Microsoft.AspNetCore.Builder;
using JsonConverter = System.Text.Json.Serialization.JsonConverter;
namespace ASC.Api.Core;

View File

@ -76,13 +76,6 @@ public class CustomEndpointDataSource : EndpointDataSource
public static class EndpointExtension
{
private static readonly IReadOnlyList<string> _methodList = new List<string>
{
"POST",
"PUT",
"DELETE"
};
public static async Task<IEndpointRouteBuilder> MapCustomAsync(this IEndpointRouteBuilder endpoints, bool webhooksEnabled = false, IServiceProvider serviceProvider = null)
{
endpoints.MapControllers();
@ -109,7 +102,7 @@ public static class EndpointExtension
var httpMethodMetadata = r.Metadata.OfType<HttpMethodMetadata>().FirstOrDefault();
var disabled = r.Metadata.OfType<WebhookDisableAttribute>().FirstOrDefault();
if (disabled == null)
if (disabled == null && httpMethodMetadata != null)
{
foreach (var httpMethod in httpMethodMetadata.HttpMethods)
{
@ -118,7 +111,7 @@ public static class EndpointExtension
}
return result;
})
.Where(r => _methodList.Contains(r.Method))
.Where(r => DbWorker.MethodList.Contains(r.Method))
.DistinctBy(r => $"{r.Method}|{r.Route}")
.ToList();

View File

@ -51,7 +51,9 @@ public class WebhooksGlobalFilterAttribute : ResultFilterAttribute, IDisposable
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
if (!await Skip(context.HttpContext))
var skip = await Skip(context.HttpContext);
if (!skip)
{
_bodyStream = context.HttpContext.Response.Body;
context.HttpContext.Response.Body = _stream;
@ -59,7 +61,7 @@ public class WebhooksGlobalFilterAttribute : ResultFilterAttribute, IDisposable
await base.OnResultExecutionAsync(context, next);
if (context.Cancel || await Skip(context.HttpContext))
if (context.Cancel || skip)
{
return;
}
@ -113,6 +115,11 @@ public class WebhooksGlobalFilterAttribute : ResultFilterAttribute, IDisposable
return true;
}
if (!DbWorker.MethodList.Contains(method))
{
return true;
}
var webhook = await _dbWorker.GetWebhookAsync(method, routePattern);
if (webhook == null || _settingsManager.Load<WebHooksSettings>().Ids.Contains(webhook.Id))
{

View File

@ -30,16 +30,15 @@ public class IPGeolocationInfo
{
public string Key { get; set; }
public string City { get; set; }
public double TimezoneOffset { get; set; }
public float TimezoneOffset { get; set; }
public string TimezoneName { get; set; }
public string IPStart { get; set; }
public string IPEnd { get; set; }
public IPAddress IPStart { get; set; }
public IPAddress IPEnd { get; set; }
public static readonly IPGeolocationInfo Default = new IPGeolocationInfo
{
Key = string.Empty,
IPStart = string.Empty,
IPEnd = string.Empty,
City = string.Empty,
TimezoneName = string.Empty,
};

View File

@ -326,6 +326,17 @@ public class TenantManager
return result;
}
public Dictionary<string, decimal> GetProductPriceInfo(string productId)
{
if (string.IsNullOrEmpty(productId))
{
return null;
}
var prices = TariffService.GetProductPriceInfo(new[] { productId });
return prices.ContainsKey(productId) ? prices[productId] : null;
}
public TenantQuota SaveTenantQuota(TenantQuota quota)
{
quota = QuotaService.SaveTenantQuota(quota);

View File

@ -24,7 +24,7 @@
// 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.Core;
namespace ASC.Core;
[Scope]
public class RegionHelper
@ -46,9 +46,8 @@ public class RegionHelper
_userManager = userManager;
}
public RegionInfo GetCurrentRegionInfo()
public RegionInfo GetCurrentRegionInfo(IDictionary<string, Dictionary<string, decimal>> priceInfo = null)
{
var priceInfo = _tenantManager.GetProductPriceInfo();
var defaultRegion = GetDefaultRegionInfo();
var countryCode = _httpContextAccessor.HttpContext.Request.Query["country"];
@ -57,6 +56,8 @@ public class RegionHelper
if (currentRegion != null && !currentRegion.Name.Equals(defaultRegion.Name))
{
priceInfo ??= _tenantManager.GetProductPriceInfo();
if (priceInfo.Values.Any(value => value.ContainsKey(currentRegion.ISOCurrencySymbol)))
{
return currentRegion;
@ -65,6 +66,7 @@ public class RegionHelper
return defaultRegion;
}
public RegionInfo GetDefaultRegionInfo()
{
return GetRegionInfo("US");

View File

@ -26,7 +26,7 @@
namespace ASC.Core.Data;
[Scope]
[Scope(Additional = typeof(DbQuotaServiceExtensions))]
class DbQuotaService : IQuotaService
{
private readonly IDbContextFactory<CoreDbContext> _dbContextFactory;
@ -41,19 +41,14 @@ class DbQuotaService : IQuotaService
{
using var coreDbContext = _dbContextFactory.CreateDbContext();
return coreDbContext.Quotas
.ProjectTo<TenantQuota>(_mapper.ConfigurationProvider)
.ToList();
return _mapper.Map<List<DbQuota>, List<TenantQuota>>(coreDbContext.Quotas.ToList());
}
public TenantQuota GetTenantQuota(int id)
{
using var coreDbContext = _dbContextFactory.CreateDbContext();
return coreDbContext.Quotas
.Where(r => r.Tenant == id)
.ProjectTo<TenantQuota>(_mapper.ConfigurationProvider)
.SingleOrDefault();
return _mapper.Map<DbQuota, TenantQuota>(coreDbContext.Quotas.SingleOrDefault(r => r.Tenant == id));
}
public TenantQuota SaveTenantQuota(TenantQuota quota)
@ -136,3 +131,11 @@ class DbQuotaService : IQuotaService
return q.ProjectTo<TenantQuotaRow>(_mapper.ConfigurationProvider).ToList();
}
}
public static class DbQuotaServiceExtensions
{
public static void Register(DIHelper services)
{
services.TryAdd<TenantQuotaPriceResolver>();
}
}

View File

@ -29,7 +29,7 @@ namespace ASC.Core.Common.EF.Context;
public class CustomDbContext : DbContext
{
public DbSet<MobileAppInstall> MobileAppInstall { get; set; }
public DbSet<DbipLocation> DbipLocation { get; set; }
public DbSet<DbIPLookup> DbIPLookup { get; set; }
public DbSet<Regions> Regions { get; set; }
public CustomDbContext(DbContextOptions<CustomDbContext> options) : base(options) { }
@ -39,7 +39,7 @@ public class CustomDbContext : DbContext
ModelBuilderWrapper
.From(modelBuilder, Database)
.AddMobileAppInstall()
.AddDbipLocation()
.AddDbIPLookup()
.AddRegions();
}
}

View File

@ -0,0 +1,155 @@
// (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.Core.Common.EF.Model;
public class DbIPLookup
{
public string AddrType { get; set; } //ipv4, ipv6
public byte[] IPStart { get; set; }
public byte[] IPEnd { get; set; }
public string Continent { get; set; }
public string Country { get; set; }
public string StateProvCode { get; set; }
public string StateProv { get; set; }
public string District { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public float Latitude { get; set; }
public float Longitude { get; set; }
public int? GeonameId { get; set; }
public float TimezoneOffset { get; set; }
public string TimezoneName { get; set; }
public string WeatherCode { get; set; }
}
public static class DbIPLookupExtension
{
public static ModelBuilderWrapper AddDbIPLookup(this ModelBuilderWrapper modelBuilder)
{
modelBuilder
.Add(MySqlAddDbIPLookup, Provider.MySql)
.Add(PgSqlAddDbIPLookup, Provider.PostgreSql);
return modelBuilder;
}
public static void MySqlAddDbIPLookup(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<DbIPLookup>(entity =>
{
entity.ToTable("dbip_lookup")
.HasCharSet("utf8mb4");
entity.HasKey(nameof(DbIPLookup.AddrType), nameof(DbIPLookup.IPStart));
entity.Property(e => e.AddrType)
.IsRequired()
.HasColumnName("addr_type")
.HasColumnType("enum('ipv4','ipv6')");
entity.Property(e => e.IPStart)
.IsRequired()
.HasColumnName("ip_start")
.HasColumnType("varbinary(16)");
entity.Property(e => e.IPEnd)
.IsRequired()
.HasColumnName("ip_end")
.HasColumnType("varbinary(16)");
entity.Property(e => e.Continent)
.IsRequired()
.HasColumnName("continent")
.HasColumnType("char(2)");
entity.Property(e => e.Country)
.IsRequired()
.HasColumnName("country")
.HasColumnType("char(2)");
entity.Property(e => e.StateProvCode)
.HasColumnName("stateprov_code")
.HasColumnType("varchar(15)");
entity.Property(e => e.StateProv)
.IsRequired()
.HasColumnName("stateprov")
.HasColumnType("varchar(80)");
entity.Property(e => e.District)
.IsRequired()
.HasColumnName("district")
.HasColumnType("varchar(80)");
entity.Property(e => e.City)
.IsRequired()
.HasColumnName("city")
.HasColumnType("varchar(80)");
entity.Property(e => e.ZipCode)
.HasColumnName("zipcode")
.HasColumnType("varchar(20)");
entity.Property(e => e.Latitude)
.IsRequired()
.HasColumnName("latitude")
.HasColumnType("float");
entity.Property(e => e.Longitude)
.IsRequired()
.HasColumnName("longitude")
.HasColumnType("float");
entity.Property(e => e.GeonameId)
.IsRequired(false)
.HasColumnName("geoname_id")
.HasColumnType("int(10)");
entity.Property(e => e.TimezoneOffset)
.IsRequired()
.HasColumnType("float")
.HasColumnName("timezone_offset");
entity.Property(e => e.TimezoneName)
.IsRequired()
.HasColumnName("timezone_name")
.HasColumnType("varchar(64)");
entity.Property(e => e.WeatherCode)
.IsRequired()
.HasColumnName("weather_code")
.HasColumnType("varchar(10)");
});
}
public static void PgSqlAddDbIPLookup(this ModelBuilder modelBuilder)
{
throw new NotImplementedException();
}
}

View File

@ -1,225 +0,0 @@
// (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.Core.Common.EF.Model;
public class DbipLocation
{
public int Id { get; set; }
public string AddrType { get; set; }
public string IPStart { get; set; }
public string IPEnd { get; set; }
public string Country { get; set; }
public string StateProv { get; set; }
public string District { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public long? Latitude { get; set; }
public long? Longitude { get; set; }
public int? GeonameId { get; set; }
public double? TimezoneOffset { get; set; }
public string TimezoneName { get; set; }
public int Processed { get; set; }
}
public static class DbipLocationExtension
{
public static ModelBuilderWrapper AddDbipLocation(this ModelBuilderWrapper modelBuilder)
{
modelBuilder
.Add(MySqlAddDbipLocation, Provider.MySql)
.Add(PgSqlAddDbipLocation, Provider.PostgreSql);
return modelBuilder;
}
public static void MySqlAddDbipLocation(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<DbipLocation>(entity =>
{
entity.ToTable("dbip_location")
.HasCharSet("utf8");
entity.HasIndex(e => e.IPStart)
.HasDatabaseName("ip_start");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.AddrType)
.IsRequired()
.HasColumnName("addr_type")
.HasColumnType("enum('ipv4','ipv6')")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.City)
.IsRequired()
.HasColumnName("city")
.HasColumnType("varchar(255)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Country)
.IsRequired()
.HasColumnName("country")
.HasColumnType("varchar(2)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.District)
.HasColumnName("district")
.HasColumnType("varchar(255)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.GeonameId)
.HasColumnName("geoname_id")
.IsRequired(false)
.HasDefaultValueSql("NULL");
entity.Property(e => e.IPEnd)
.IsRequired()
.HasColumnName("ip_end")
.HasColumnType("varchar(39)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.IPStart)
.IsRequired()
.HasColumnName("ip_start")
.HasColumnType("varchar(39)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Latitude)
.HasColumnName("latitude")
.HasColumnType("float")
.IsRequired(false)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Longitude)
.HasColumnName("longitude")
.HasColumnType("float")
.IsRequired(false)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Processed)
.HasColumnName("processed")
.HasDefaultValueSql("'1'");
entity.Property(e => e.StateProv)
.IsRequired()
.HasColumnName("stateprov")
.HasColumnType("varchar(255)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.TimezoneName)
.HasColumnName("timezone_name")
.HasColumnType("varchar(255)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.TimezoneOffset)
.HasColumnType("int")
.HasColumnName("timezone_offset")
.IsRequired(false)
.HasDefaultValueSql("NULL");
entity.Property(e => e.ZipCode)
.HasColumnName("zipcode")
.HasColumnType("varchar(255)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
});
}
public static void PgSqlAddDbipLocation(this ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresEnum("onlyoffice", "enum_dbip_location", new[] { "ipv4", "ipv6" });
modelBuilder.Entity<DbipLocation>(entity =>
{
entity.ToTable("dbip_location", "onlyoffice");
entity.HasIndex(e => e.IPStart)
.HasDatabaseName("ip_start");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.City)
.IsRequired()
.HasColumnName("city")
.HasMaxLength(255);
entity.Property(e => e.Country)
.IsRequired()
.HasColumnName("country")
.HasMaxLength(2);
entity.Property(e => e.District)
.HasColumnName("district")
.HasMaxLength(255)
.HasDefaultValueSql("NULL");
entity.Property(e => e.GeonameId).HasColumnName("geoname_id");
entity.Property(e => e.IPEnd)
.IsRequired()
.HasColumnName("ip_end")
.HasMaxLength(39);
entity.Property(e => e.IPStart)
.IsRequired()
.HasColumnName("ip_start")
.HasMaxLength(39);
entity.Property(e => e.Latitude).HasColumnName("latitude");
entity.Property(e => e.Longitude).HasColumnName("longitude");
entity.Property(e => e.Processed)
.HasColumnName("processed")
.HasDefaultValueSql("1");
entity.Property(e => e.StateProv)
.IsRequired()
.HasColumnName("stateprov")
.HasMaxLength(255);
entity.Property(e => e.TimezoneName)
.HasColumnName("timezone_name")
.HasMaxLength(255)
.HasDefaultValueSql("NULL");
entity.Property(e => e.TimezoneOffset).HasColumnName("timezone_offset");
entity.Property(e => e.ZipCode)
.HasColumnName("zipcode")
.HasMaxLength(255)
.HasDefaultValueSql("NULL");
});
}
}

View File

@ -26,45 +26,69 @@
namespace ASC.Geolocation;
// hack for EF Core
public static class EntityFrameworkHelper
{
public static int Compare(this byte[] b1, byte[] b2)
{
throw new Exception("This method can only be used in EF LINQ Context");
}
}
[Scope]
public class GeolocationHelper
{
private readonly CreatorDbContext _creatorDbContext;
private readonly IDbContextFactory<CustomDbContext> _dbContextFactory;
private readonly ILogger<GeolocationHelper> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ICache _cache;
public GeolocationHelper(
CreatorDbContext creatorDbContext,
IDbContextFactory<CustomDbContext> dbContextFactory,
ILogger<GeolocationHelper> logger,
IHttpContextAccessor httpContextAccessor)
IHttpContextAccessor httpContextAccessor,
ICache cache)
{
_creatorDbContext = creatorDbContext;
_dbContextFactory = dbContextFactory;
_logger = logger;
_httpContextAccessor = httpContextAccessor;
_cache = cache;
}
public IPGeolocationInfo GetIPGeolocation(string ip)
public IPGeolocationInfo GetIPGeolocation(IPAddress address)
{
try
{
using var dbContext = _creatorDbContext.CreateDbContext<CustomDbContext>(nameConnectionString: "teamlabsite");
var ipformatted = FormatIP(ip);
var q = dbContext.DbipLocation
.Where(r => r.IPStart.CompareTo(ipformatted) <= 0)
.Where(r => ipformatted.CompareTo(r.IPEnd) <= 0)
var cacheKey = $"ip_geolocation_info_${address}";
var fromCache = _cache.Get<IPGeolocationInfo>(cacheKey);
if (fromCache != null) return fromCache;
using var dbContext = _dbContextFactory.CreateDbContext();
var addrType = address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? "ipv4" : "ipv6";
var result = dbContext.DbIPLookup
.Where(r => r.AddrType == addrType && r.IPStart.Compare(address.GetAddressBytes()) <= 0)
.OrderByDescending(r => r.IPStart)
.Select(r => new IPGeolocationInfo
{
City = r.City,
IPEnd = r.IPEnd,
IPStart = r.IPStart,
IPEnd = new IPAddress(r.IPEnd),
IPStart = new IPAddress(r.IPStart),
Key = r.Country,
TimezoneOffset = r.TimezoneOffset ?? 0,
TimezoneOffset = r.TimezoneOffset,
TimezoneName = r.TimezoneName
})
.FirstOrDefault();
return q ?? IPGeolocationInfo.Default;
if (result != null)
{
_cache.Insert(cacheKey, result, TimeSpan.FromSeconds(15));
}
return result ?? IPGeolocationInfo.Default;
}
catch (Exception error)
{
@ -84,44 +108,10 @@ public class GeolocationHelper
{
_logger.DebugRemoteIpAddress(ip.ToString());
return GetIPGeolocation(ip.ToString());
return GetIPGeolocation(ip);
}
}
return IPGeolocationInfo.Default;
}
private static string FormatIP(string ip)
{
ip = (ip ?? "").Trim();
if (ip.Contains('.'))
{
//ip v4
if (ip.Length == 15)
{
return ip;
}
return string.Join(".", ip.Split(':')[0].Split('.').Select(s => ("00" + s).Substring(s.Length - 1)).ToArray());
}
else if (ip.Contains(':'))
{
//ip v6
if (ip.Length == 39)
{
return ip;
}
var index = ip.IndexOf("::");
if (0 <= index)
{
ip = ip.Insert(index + 2, new string(':', 8 - ip.Split(':').Length));
}
return string.Join(":", ip.Split(':').Select(s => ("0000" + s).Substring(s.Length)).ToArray());
}
else
{
throw new ArgumentException("Unknown ip " + ip);
}
}
}

View File

@ -27,7 +27,7 @@
namespace ASC.Core.Common.Log;
internal static partial class GeolocationHelperLogger
{
[LoggerMessage(Level = LogLevel.Error, Message = "This is remote ip address {remoteIp}")]
[LoggerMessage(Level = LogLevel.Debug, Message = "This is remote ip address {remoteIp}")]
public static partial void DebugRemoteIpAddress(this ILogger<GeolocationHelper> logger, string remoteIp);
[LoggerMessage(Level = LogLevel.Error, Message = "GetIPGeolocation")]

View File

@ -42,6 +42,7 @@ public class TenantQuota : IMapFrom<DbQuota>
public int Tenant { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string PriceCurrencySymbol { get; set; }
public string ProductId { get; set; }
public bool Visible { get; set; }
@ -373,7 +374,8 @@ public class TenantQuota : IMapFrom<DbQuota>
public void Mapping(Profile profile)
{
profile.CreateMap<DbQuota, TenantQuota>();
profile.CreateMap<DbQuota, TenantQuota>()
.ForMember(dest => dest.Price, o => o.MapFrom<TenantQuotaPriceResolver>());
}
public TenantQuotaFeature<T> GetFeature<T>(string name)

View File

@ -0,0 +1,58 @@
// (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.Core.Common.Tenants;
[Scope]
internal class TenantQuotaPriceResolver : IValueResolver<DbQuota, TenantQuota, decimal>
{
private readonly TenantManager _tenantManager;
private readonly RegionHelper _regionHelper;
public TenantQuotaPriceResolver(TenantManager tenantManager, RegionHelper regionHelper)
{
_tenantManager = tenantManager;
_regionHelper = regionHelper;
}
public decimal Resolve(DbQuota source, TenantQuota destination, decimal destMember, ResolutionContext context)
{
var priceInfo = _tenantManager.GetProductPriceInfo(source.ProductId);
if (priceInfo != null)
{
var currentRegion = _regionHelper.GetCurrentRegionInfo(new Dictionary<string, Dictionary<string, decimal>>() { { source.ProductId, priceInfo } });
destination.PriceCurrencySymbol = currentRegion.CurrencySymbol;
if (priceInfo.ContainsKey(currentRegion.ISOCurrencySymbol))
{
return priceInfo[currentRegion.ISOCurrencySymbol];
}
}
return source.Price;
}
}

View File

@ -43,6 +43,7 @@ public class TenantsModuleSpecifics : ModuleSpecificsBase
{
DateColumns = new Dictionary<string, bool> {{"creationdatetime", false}, {"statuschanged", false}, {"version_changed", false}}
},
new TableInfo("tenants_tariffrow", "tenant") {InsertMethod = InsertMethod.Replace},
new TableInfo("tenants_quotarow", "tenant") {InsertMethod = InsertMethod.Replace},
new TableInfo("core_user", "tenant", "id", IdType.Guid)
{
@ -58,6 +59,7 @@ public class TenantsModuleSpecifics : ModuleSpecificsBase
new RelationInfo("tenants_tenants", "id", "tenants_quota", "tenant"),
new RelationInfo("tenants_tenants", "id", "tenants_tariff", "tenant"),
new RelationInfo("tenants_tenants", "id", "tenants_tariff", "tariff"),
new RelationInfo("tenants_tariff", "id", "tenants_tariffrow", "tariff_id"),
new RelationInfo("core_user", "id", "tenants_tenants", "owner_id", null, null, RelationImportance.Low)
};

View File

@ -31,6 +31,13 @@ namespace ASC.Webhooks.Core;
[Scope]
public class DbWorker
{
public static readonly IReadOnlyList<string> MethodList = new List<string>
{
"POST",
"PUT",
"DELETE"
};
private readonly IDbContextFactory<WebhooksDbContext> _dbContextFactory;
private readonly TenantManager _tenantManager;
private readonly AuthContext _authContext;

View File

@ -243,7 +243,7 @@ public class ConnectionsController : ControllerBase
{
try
{
var location = _geolocationHelper.GetIPGeolocation(ip);
var location = _geolocationHelper.GetIPGeolocation(IPAddress.Parse(ip));
if (string.IsNullOrEmpty(location.Key))
{
return new string[] { string.Empty, string.Empty };

View File

@ -30,40 +30,33 @@ namespace ASC.Web.Api.Core;
public class QuotaHelper
{
private readonly TenantManager _tenantManager;
private readonly RegionHelper _regionHelper;
private readonly IServiceProvider _serviceProvider;
public QuotaHelper(TenantManager tenantManager, RegionHelper regionHelper, IServiceProvider serviceProvider)
public QuotaHelper(TenantManager tenantManager, IServiceProvider serviceProvider)
{
_tenantManager = tenantManager;
_regionHelper = regionHelper;
_serviceProvider = serviceProvider;
}
public async IAsyncEnumerable<QuotaDto> GetQuotas()
{
var quotaList = _tenantManager.GetTenantQuotas(false);
var priceInfo = _tenantManager.GetProductPriceInfo();
var currentRegion = _regionHelper.GetCurrentRegionInfo();
foreach (var quota in quotaList)
{
yield return await ToQuotaDto(quota, priceInfo, currentRegion);
yield return await ToQuotaDto(quota);
}
}
public async Task<QuotaDto> GetCurrentQuota(bool refresh = false)
{
var quota = _tenantManager.GetCurrentTenantQuota(refresh);
var priceInfo = _tenantManager.GetProductPriceInfo();
var currentRegion = _regionHelper.GetCurrentRegionInfo();
return await ToQuotaDto(quota, priceInfo, currentRegion, true, true);
return await ToQuotaDto(quota, true, true);
}
private async Task<QuotaDto> ToQuotaDto(TenantQuota quota, IDictionary<string, Dictionary<string, decimal>> priceInfo, RegionInfo currentRegion, bool getUsed = false, bool allFeatures = false)
private async Task<QuotaDto> ToQuotaDto(TenantQuota quota, bool getUsed = false, bool allFeatures = false)
{
var price = GetPrice(quota, priceInfo, currentRegion);
var features = await GetFeatures(quota, getUsed, allFeatures).ToListAsync();
return new QuotaDto
@ -77,27 +70,14 @@ public class QuotaHelper
Price = new PriceDto
{
Value = price,
CurrencySymbol = currentRegion.CurrencySymbol
Value = quota.Price,
CurrencySymbol = quota.PriceCurrencySymbol
},
Features = features
};
}
private decimal GetPrice(TenantQuota quota, IDictionary<string, Dictionary<string, decimal>> priceInfo, RegionInfo currentRegion)
{
if (!string.IsNullOrEmpty(quota.Name) && priceInfo.ContainsKey(quota.Name))
{
var prices = priceInfo[quota.Name];
if (prices.ContainsKey(currentRegion.ISOCurrencySymbol))
{
return prices[currentRegion.ISOCurrencySymbol];
}
}
return quota.Price;
}
private async IAsyncEnumerable<TenantQuotaFeatureDto> GetFeatures(TenantQuota quota, bool getUsed, bool all)
{
var assembly = GetType().Assembly;