Common, db: moved from 08a01422
This commit is contained in:
parent
31752e64b4
commit
a5c6ba5dcc
@ -25,39 +25,24 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
|
||||
using ASC.Data.Storage;
|
||||
|
||||
public static class StreamExtension
|
||||
{
|
||||
// public const int BufferSize = 2048; //NOTE: set to 2048 to fit in minimum tcp window
|
||||
public const int BufferSize = 2048; //NOTE: set to 2048 to fit in minimum tcp window
|
||||
|
||||
public static void StreamCopyTo(this Stream srcStream, Stream dstStream, int length)
|
||||
{
|
||||
if (srcStream == null) throw new ArgumentNullException("srcStream");
|
||||
if (dstStream == null) throw new ArgumentNullException("dstStream");
|
||||
|
||||
public static Stream GetBuffered(this Stream srcStream)
|
||||
{
|
||||
if (srcStream == null) throw new ArgumentNullException(nameof(srcStream));
|
||||
if (!srcStream.CanSeek || srcStream.CanTimeout)
|
||||
{
|
||||
//Buffer it
|
||||
var memStream = TempStream.Create();
|
||||
srcStream.CopyTo(memStream);
|
||||
memStream.Position = 0;
|
||||
return memStream;
|
||||
}
|
||||
return srcStream;
|
||||
}
|
||||
|
||||
public static byte[] GetCorrectBuffer(this Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
|
||||
using var mem = stream.GetBuffered();
|
||||
var buffer = new byte[mem.Length];
|
||||
mem.Position = 0;
|
||||
mem.Read(buffer, 0, buffer.Length);
|
||||
return buffer;
|
||||
var buffer = new byte[BufferSize];
|
||||
int totalRead = 0;
|
||||
int readed;
|
||||
while ((readed = srcStream.Read(buffer, 0, length - totalRead > BufferSize ? BufferSize : length - totalRead)) > 0 && totalRead < length)
|
||||
{
|
||||
dstStream.Write(buffer, 0, readed);
|
||||
totalRead += readed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +1,52 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace ASC.Data.Storage
|
||||
{
|
||||
public static class TempStream
|
||||
{
|
||||
public static Stream Create()
|
||||
{
|
||||
//Return temporary stream
|
||||
return new FileStream(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 2048, FileOptions.DeleteOnClose);
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2021
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ASC.Common
|
||||
{
|
||||
[Singletone]
|
||||
public class TempStream
|
||||
{
|
||||
private TempPath TempPath { get; }
|
||||
|
||||
public TempStream(TempPath tempPath)
|
||||
{
|
||||
TempPath = tempPath;
|
||||
}
|
||||
|
||||
public Stream GetBuffered(Stream srcStream)
|
||||
{
|
||||
if (srcStream == null) throw new ArgumentNullException("srcStream");
|
||||
if (!srcStream.CanSeek || srcStream.CanTimeout)
|
||||
{
|
||||
//Buffer it
|
||||
var memStream = Create();
|
||||
srcStream.CopyTo(memStream);
|
||||
memStream.Position = 0;
|
||||
return memStream;
|
||||
}
|
||||
return srcStream;
|
||||
}
|
||||
|
||||
public Stream Create()
|
||||
{
|
||||
return new FileStream(TempPath.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ using System.Reflection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
|
||||
|
||||
@ -163,15 +164,17 @@ namespace System.Web
|
||||
}
|
||||
|
||||
public static bool DesktopApp(this HttpRequest request)
|
||||
{
|
||||
return request != null && !string.IsNullOrEmpty(request.Headers["desktop"]);
|
||||
{
|
||||
return request != null
|
||||
&& (!string.IsNullOrEmpty(request.Query["desktop"])
|
||||
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("AscDesktopEditor"));
|
||||
}
|
||||
|
||||
public static bool SailfishApp(this HttpRequest request)
|
||||
{
|
||||
return request != null
|
||||
&& (!string.IsNullOrEmpty(request.Headers["sailfish"])
|
||||
|| !string.IsNullOrEmpty(request.Headers["User-Agent"]) && request.Headers["User-Agent"].ToString().Contains("SailfishOS"));
|
||||
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("SailfishOS"));
|
||||
}
|
||||
|
||||
|
||||
|
@ -238,10 +238,10 @@ namespace ASC.Core.Common
|
||||
return baseUri.ToString().TrimEnd('/');
|
||||
}
|
||||
|
||||
public void Initialize(string serverUri)
|
||||
public void Initialize(string serverUri, bool localhost = true)
|
||||
{
|
||||
var uri = new Uri(serverUri.Replace('*', 'x').Replace('+', 'x'));
|
||||
_serverRoot = new UriBuilder(uri.Scheme, LOCALHOST, uri.Port);
|
||||
_serverRoot = new UriBuilder(uri.Scheme, localhost ? LOCALHOST : uri.Host, uri.Port);
|
||||
_vpath = "/" + uri.AbsolutePath.Trim('/');
|
||||
}
|
||||
}
|
||||
|
@ -26,249 +26,271 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Cryptography;
|
||||
using System.ServiceModel;
|
||||
using System.Web;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
|
||||
using ASC.Common.Logging;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using ASC.Common;
|
||||
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Billing
|
||||
{
|
||||
public class BillingClient : ClientBase<IService>, IDisposable
|
||||
{
|
||||
private readonly ILog log;
|
||||
private readonly bool test;
|
||||
|
||||
private string Security { get; set; }
|
||||
private string PartnersProduct { get; set; }
|
||||
|
||||
public BillingClient(IConfiguration configuration, IOptionsMonitor<ILog> option)
|
||||
: this(false, configuration, option)
|
||||
{
|
||||
}
|
||||
|
||||
public BillingClient(bool test, IConfiguration configuration, IOptionsMonitor<ILog> option)
|
||||
{
|
||||
this.test = test;
|
||||
Security = configuration["core:payment:security"];
|
||||
PartnersProduct = configuration["core:payment:partners-product"];
|
||||
log = option.CurrentValue;
|
||||
}
|
||||
|
||||
|
||||
public PaymentLast GetLastPayment(string portalId)
|
||||
{
|
||||
var result = Request("GetLatestActiveResourceEx", portalId);
|
||||
var xelement = ToXElement("<root>" + result + "</root>");
|
||||
var dedicated = xelement.Element("dedicated-resource");
|
||||
var payment = xelement.Element("payment");
|
||||
|
||||
if (!test && GetValueString(payment.Element("status")) == "4")
|
||||
{
|
||||
throw new BillingException("Can not accept test payment.", new { PortalId = portalId });
|
||||
}
|
||||
|
||||
var autorenewal = string.Empty;
|
||||
try
|
||||
{
|
||||
autorenewal = Request("GetLatestAvangateLicenseRecurringStatus", portalId);
|
||||
}
|
||||
catch (BillingException err)
|
||||
{
|
||||
log.Debug(err); // ignore
|
||||
}
|
||||
|
||||
return new PaymentLast
|
||||
{
|
||||
[Singletone]
|
||||
public class BillingClient
|
||||
{
|
||||
public readonly bool Configured = false;
|
||||
private readonly string _billingDomain;
|
||||
private readonly string _billingKey;
|
||||
private readonly string _billingSecret;
|
||||
private readonly bool _test;
|
||||
|
||||
private const int AvangatePaymentSystemId = 1;
|
||||
|
||||
|
||||
public BillingClient(IConfiguration configuration)
|
||||
: this(false, configuration)
|
||||
{
|
||||
}
|
||||
|
||||
public BillingClient(bool test, IConfiguration configuration)
|
||||
{
|
||||
_test = test;
|
||||
|
||||
var billingDomain = configuration["core:payment-url"];
|
||||
|
||||
_billingDomain = (billingDomain ?? "").Trim().TrimEnd('/');
|
||||
if (!string.IsNullOrEmpty(_billingDomain))
|
||||
{
|
||||
ProductId = GetValueString(dedicated.Element("product-id")),
|
||||
EndDate = GetValueDateTime(dedicated.Element("end-date")),
|
||||
Autorenewal = "enabled".Equals(autorenewal, StringComparison.InvariantCultureIgnoreCase),
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<PaymentInfo> GetPayments(string portalId, DateTime from, DateTime to)
|
||||
{
|
||||
string result;
|
||||
if (from == DateTime.MinValue && to == DateTime.MaxValue)
|
||||
{
|
||||
result = Request("GetPayments", portalId);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Request("GetListOfPaymentsByTimeSpan", portalId, Tuple.Create("StartDate", from.ToString("yyyy-MM-dd HH:mm:ss")), Tuple.Create("EndDate", to.ToString("yyyy-MM-dd HH:mm:ss")));
|
||||
}
|
||||
var xelement = ToXElement(result);
|
||||
return xelement.Elements("payment").Select(ToPaymentInfo);
|
||||
}
|
||||
|
||||
public IDictionary<string, Tuple<Uri, Uri>> GetPaymentUrls(string portalId, string[] products, string affiliateId = null, string campaign = null, string currency = null, string language = null, string customerId = null)
|
||||
{
|
||||
var urls = new Dictionary<string, Tuple<Uri, Uri>>();
|
||||
|
||||
var additionalParameters = new List<Tuple<string, string>>(2) { Tuple.Create("PaymentSystemId", "1") };
|
||||
if (!string.IsNullOrEmpty(affiliateId))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("AffiliateId", affiliateId));
|
||||
_billingDomain += "/billing/";
|
||||
|
||||
_billingKey = configuration["core:payment-key"];
|
||||
_billingSecret = configuration["core:payment-secret"];
|
||||
|
||||
Configured = true;
|
||||
}
|
||||
}
|
||||
|
||||
public PaymentLast GetLastPayment(string portalId)
|
||||
{
|
||||
var result = Request("GetActiveResource", portalId);
|
||||
var paymentLast = JsonSerializer.Deserialize<PaymentLast>(result);
|
||||
|
||||
if (!_test && paymentLast.PaymentStatus == 4)
|
||||
{
|
||||
throw new BillingException("Can not accept test payment.", new { PortalId = portalId });
|
||||
}
|
||||
|
||||
return paymentLast;
|
||||
}
|
||||
|
||||
public IEnumerable<PaymentInfo> GetPayments(string portalId)
|
||||
{
|
||||
string result = Request("GetPayments", portalId);
|
||||
var payments = JsonSerializer.Deserialize<List<PaymentInfo>>(result);
|
||||
|
||||
return payments;
|
||||
}
|
||||
|
||||
public IDictionary<string, Tuple<Uri, Uri>> GetPaymentUrls(string portalId, string[] products, string affiliateId = null, string campaign = null, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
{
|
||||
var urls = new Dictionary<string, Tuple<Uri, Uri>>();
|
||||
|
||||
var additionalParameters = new List<Tuple<string, string>>() { Tuple.Create("PaymentSystemId", AvangatePaymentSystemId.ToString()) };
|
||||
if (!string.IsNullOrEmpty(affiliateId))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("AffiliateId", affiliateId));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(campaign))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("campaign", campaign));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(currency))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Currency", currency));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(language))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Language", language));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(customerId))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("CustomerID", customerId));
|
||||
}
|
||||
|
||||
var parameters = products
|
||||
.Distinct()
|
||||
.Select(p => Tuple.Create("ProductId", p))
|
||||
.Concat(additionalParameters)
|
||||
.ToArray();
|
||||
|
||||
//max 100 products
|
||||
var paymentUrls = ToXElement(Request("GetBatchPaymentSystemUrl", portalId, parameters))
|
||||
.Elements()
|
||||
.ToDictionary(e => e.Attribute("id").Value, e => ToUrl(e.Attribute("value").Value));
|
||||
|
||||
var upgradeUrls = new Dictionary<string, string>();
|
||||
if (!string.IsNullOrEmpty(portalId))
|
||||
{
|
||||
try
|
||||
{
|
||||
//max 100 products
|
||||
upgradeUrls = ToXElement(Request("GetBatchPaymentSystemUpgradeUrl", portalId, parameters))
|
||||
.Elements()
|
||||
.ToDictionary(e => e.Attribute("id").Value, e => ToUrl(e.Attribute("value").Value));
|
||||
}
|
||||
catch (BillingException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var p in products)
|
||||
{
|
||||
var paymentUrl = (Uri)null;
|
||||
var upgradeUrl = (Uri)null;
|
||||
if (paymentUrls.TryGetValue(p, out var url) && !string.IsNullOrEmpty(url))
|
||||
{
|
||||
paymentUrl = new Uri(url);
|
||||
}
|
||||
if (upgradeUrls.TryGetValue(p, out url) && !string.IsNullOrEmpty(url))
|
||||
{
|
||||
upgradeUrl = new Uri(url);
|
||||
}
|
||||
urls[p] = Tuple.Create(paymentUrl, upgradeUrl);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
public Invoice GetInvoice(string paymentId)
|
||||
{
|
||||
var result = Request("GetInvoice", null, Tuple.Create("PaymentId", paymentId));
|
||||
var xelement = ToXElement(result);
|
||||
return new Invoice
|
||||
{
|
||||
Sale = GetValueString(xelement.Element("sale")),
|
||||
Refund = GetValueString(xelement.Element("refund")),
|
||||
};
|
||||
}
|
||||
if (!string.IsNullOrEmpty(currency))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Currency", currency));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(language))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Language", language));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(customerId))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("CustomerID", customerId));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(quantity))
|
||||
{
|
||||
additionalParameters.Add(Tuple.Create("Quantity", quantity));
|
||||
}
|
||||
|
||||
var parameters = products
|
||||
.Distinct()
|
||||
.Select(p => Tuple.Create("ProductId", p))
|
||||
.Concat(additionalParameters)
|
||||
.ToArray();
|
||||
|
||||
//max 100 products
|
||||
var result = Request("GetPaymentUrl", portalId, parameters);
|
||||
var paymentUrls = JsonSerializer.Deserialize<Dictionary<string, string>>(result);
|
||||
|
||||
var upgradeUrls = new Dictionary<string, string>();
|
||||
if (!string.IsNullOrEmpty(portalId)
|
||||
//TODO: remove
|
||||
&& false)
|
||||
{
|
||||
try
|
||||
{
|
||||
//max 100 products
|
||||
result = Request("GetPaymentUpgradeUrl", portalId, parameters);
|
||||
upgradeUrls = JsonSerializer.Deserialize<Dictionary<string, string>>(result);
|
||||
}
|
||||
catch (BillingNotFoundException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var p in products)
|
||||
{
|
||||
string url;
|
||||
var paymentUrl = (Uri)null;
|
||||
var upgradeUrl = (Uri)null;
|
||||
if (paymentUrls.TryGetValue(p, out url) && !string.IsNullOrEmpty(url = ToUrl(url)))
|
||||
{
|
||||
paymentUrl = new Uri(url);
|
||||
}
|
||||
if (upgradeUrls.TryGetValue(p, out url) && !string.IsNullOrEmpty(url = ToUrl(url)))
|
||||
{
|
||||
upgradeUrl = new Uri(url);
|
||||
}
|
||||
urls[p] = Tuple.Create(paymentUrl, upgradeUrl);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
public IDictionary<string, IEnumerable<Tuple<string, decimal>>> GetProductPriceInfo(params string[] productIds)
|
||||
public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds)
|
||||
{
|
||||
if (productIds == null)
|
||||
{
|
||||
throw new ArgumentNullException("productIds");
|
||||
}
|
||||
|
||||
var responce = Request("GetBatchAvangateProductPriceInfo", null, productIds.Select(pid => Tuple.Create("ProductId", pid)).ToArray());
|
||||
var xelement = ToXElement(responce);
|
||||
return productIds
|
||||
.Select(p =>
|
||||
var parameters = productIds.Select(pid => Tuple.Create("ProductId", pid)).ToList();
|
||||
parameters.Add(Tuple.Create("PaymentSystemId", AvangatePaymentSystemId.ToString()));
|
||||
|
||||
var result = Request("GetProductsPrices", null, parameters.ToArray());
|
||||
var prices = JsonSerializer.Deserialize<Dictionary<int, Dictionary<string, Dictionary<string, decimal>>>>(result);
|
||||
|
||||
if (prices.ContainsKey(AvangatePaymentSystemId))
|
||||
{
|
||||
var pricesPaymentSystem = prices[AvangatePaymentSystemId];
|
||||
|
||||
return productIds.Select(productId =>
|
||||
{
|
||||
var prices = Enumerable.Empty<Tuple<string, decimal>>();
|
||||
var product = xelement.XPathSelectElement(string.Format("/avangate-product/internal-id[text()=\"{0}\"]", p));
|
||||
if (product != null)
|
||||
if (pricesPaymentSystem.ContainsKey(productId))
|
||||
{
|
||||
prices = product.Parent.Element("prices").Elements("price-item")
|
||||
.Select(e => Tuple.Create(e.Element("currency").Value, decimal.Parse(e.Element("amount").Value)));
|
||||
return new { ProductId = productId, Prices = pricesPaymentSystem[productId] };
|
||||
}
|
||||
return new { ProductId = p, Prices = prices, };
|
||||
return new { ProductId = productId, Prices = new Dictionary<string, decimal>() };
|
||||
})
|
||||
.ToDictionary(e => e.ProductId, e => e.Prices);
|
||||
.ToDictionary(e => e.ProductId, e => e.Prices);
|
||||
}
|
||||
|
||||
return new Dictionary<string, Dictionary<string, decimal>>();
|
||||
}
|
||||
|
||||
|
||||
private string CreateAuthToken(string pkey, string machinekey)
|
||||
{
|
||||
using (var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(machinekey)))
|
||||
{
|
||||
var now = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
|
||||
var hash = WebEncoders.Base64UrlEncode(hasher.ComputeHash(Encoding.UTF8.GetBytes(string.Join("\n", now, pkey))));
|
||||
return string.Format("ASC {0}:{1}:{2}", pkey, now, hash);
|
||||
}
|
||||
}
|
||||
|
||||
private string Request(string method, string portalId, params Tuple<string, string>[] parameters)
|
||||
{
|
||||
var request = new XElement(method);
|
||||
var url = _billingDomain + method;
|
||||
|
||||
var request = WebRequest.Create(url);
|
||||
request.Method = "POST";
|
||||
request.Timeout = 60000;
|
||||
request.ContentType = "application/json";
|
||||
|
||||
if (!string.IsNullOrEmpty(_billingKey))
|
||||
{
|
||||
request.Headers.Add("Authorization", CreateAuthToken(_billingKey, _billingSecret));
|
||||
}
|
||||
|
||||
var data = new Dictionary<string, List<string>>();
|
||||
if (!string.IsNullOrEmpty(portalId))
|
||||
{
|
||||
request.Add(new XElement("PortalId", portalId));
|
||||
data.Add("PortalId", new List<string>() { portalId });
|
||||
}
|
||||
request.Add(parameters.Select(p => new XElement(p.Item1, p.Item2)).ToArray());
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
if (!data.ContainsKey(parameter.Item1))
|
||||
{
|
||||
data.Add(parameter.Item1, new List<string>() { parameter.Item2 });
|
||||
}
|
||||
else
|
||||
{
|
||||
data[parameter.Item1].Add(parameter.Item2);
|
||||
}
|
||||
}
|
||||
var body = JsonSerializer.Serialize(data);
|
||||
|
||||
var responce = Channel.Request(new Message { Type = MessageType.Data, Content = request.ToString(SaveOptions.DisableFormatting), });
|
||||
if (responce.Content == null)
|
||||
var bytes = Encoding.UTF8.GetBytes(body ?? "");
|
||||
request.ContentLength = bytes.Length;
|
||||
using (var stream = request.GetRequestStream())
|
||||
{
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
string result;
|
||||
try
|
||||
{
|
||||
using (var response = request.GetResponse())
|
||||
using (var stream = response.GetResponseStream())
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new BillingNotConfiguredException("Billing response is null");
|
||||
}
|
||||
using (var readStream = new StreamReader(stream))
|
||||
{
|
||||
result = readStream.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
request.Abort();
|
||||
throw;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result))
|
||||
{
|
||||
throw new BillingNotConfiguredException("Billing response is null");
|
||||
}
|
||||
if (responce.Type == MessageType.Data)
|
||||
if (!result.StartsWith("{\"Message\":\"error"))
|
||||
{
|
||||
var result = responce.Content;
|
||||
var invalidChar = ((char)65279).ToString();
|
||||
return result.Contains(invalidChar) ? result.Replace(invalidChar, string.Empty) : result;
|
||||
return result;
|
||||
}
|
||||
|
||||
var @params = (parameters ?? Enumerable.Empty<Tuple<string, string>>()).Select(p => string.Format("{0}: {1}", p.Item1, p.Item2));
|
||||
var info = new { Method = method, PortalId = portalId, Params = string.Join(", ", @params) };
|
||||
if (responce.Content.Contains("error: cannot find "))
|
||||
if (result.Contains("{\"Message\":\"error: cannot find "))
|
||||
{
|
||||
throw new BillingNotFoundException(responce.Content, info);
|
||||
throw new BillingNotFoundException(result, info);
|
||||
}
|
||||
throw new BillingException(responce.Content, info);
|
||||
}
|
||||
|
||||
private static XElement ToXElement(string xml)
|
||||
{
|
||||
return XElement.Parse(xml);
|
||||
}
|
||||
|
||||
private static PaymentInfo ToPaymentInfo(XElement x)
|
||||
{
|
||||
return new PaymentInfo
|
||||
{
|
||||
ID = (int)GetValueDecimal(x.Element("id")),
|
||||
Status = (int)GetValueDecimal(x.Element("status")),
|
||||
PaymentType = GetValueString(x.Element("reserved-str-2")),
|
||||
ExchangeRate = (double)GetValueDecimal(x.Element("exch-rate")),
|
||||
GrossSum = (double)GetValueDecimal(x.Element("gross-sum")),
|
||||
Name = (GetValueString(x.Element("fname")) + " " + GetValueString(x.Element("lname"))).Trim(),
|
||||
Email = GetValueString(x.Element("email")),
|
||||
Date = GetValueDateTime(x.Element("payment-date")),
|
||||
Price = GetValueDecimal(x.Element("price")),
|
||||
Currency = GetValueString(x.Element("payment-currency")),
|
||||
Method = GetValueString(x.Element("payment-method")),
|
||||
CartId = GetValueString(x.Element("cart-id")),
|
||||
ProductId = GetValueString(x.Element("product-ref")),
|
||||
TenantID = GetValueString(x.Element("customer-id")),
|
||||
Country = GetValueString(x.Element("country")),
|
||||
DiscountSum = GetValueDecimal(x.Element("discount-sum"))
|
||||
};
|
||||
throw new BillingException(result, info);
|
||||
}
|
||||
|
||||
private string ToUrl(string s)
|
||||
@ -278,55 +300,12 @@ namespace ASC.Core.Billing
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
if (test && !s.Contains("&DOTEST = 1"))
|
||||
if (_test && !s.Contains("&DOTEST = 1"))
|
||||
{
|
||||
s += "&DOTEST=1";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private static string GetValueString(XElement xelement)
|
||||
{
|
||||
return xelement != null ? HttpUtility.HtmlDecode(xelement.Value) : default;
|
||||
}
|
||||
|
||||
private static DateTime GetValueDateTime(XElement xelement)
|
||||
{
|
||||
return xelement != null ?
|
||||
DateTime.ParseExact(xelement.Value, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) :
|
||||
default;
|
||||
}
|
||||
|
||||
private static decimal GetValueDecimal(XElement xelement)
|
||||
{
|
||||
if (xelement == null || string.IsNullOrEmpty(xelement.Value))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
var sep = CultureInfo.InvariantCulture.NumberFormat.CurrencyDecimalSeparator;
|
||||
return decimal.TryParse(xelement.Value.Replace(".", sep).Replace(",", sep), NumberStyles.Currency, CultureInfo.InvariantCulture, out var value) ? value : default;
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Close();
|
||||
}
|
||||
catch (CommunicationException)
|
||||
{
|
||||
Abort();
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
Abort();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Abort();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,24 +34,22 @@ namespace ASC.Core.Billing
|
||||
[Scope(typeof(ConfigureTariffService))]
|
||||
public interface ITariffService
|
||||
{
|
||||
Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true);
|
||||
|
||||
void SetTariff(int tenantId, Tariff tariff);
|
||||
|
||||
void DeleteDefaultBillingInfo();
|
||||
|
||||
void ClearCache(int tenantId);
|
||||
|
||||
IEnumerable<PaymentInfo> GetPayments(int tenantId, DateTime from, DateTime to);
|
||||
|
||||
Uri GetShoppingUri(int? tenant, int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null);
|
||||
|
||||
IDictionary<string, IEnumerable<Tuple<string, decimal>>> GetProductPriceInfo(params string[] productIds);
|
||||
|
||||
Invoice GetInvoice(string paymentId);
|
||||
|
||||
string GetButton(int tariffId, string partnerId);
|
||||
|
||||
Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true);
|
||||
|
||||
void SetTariff(int tenantId, Tariff tariff);
|
||||
|
||||
void DeleteDefaultBillingInfo();
|
||||
|
||||
void ClearCache(int tenantId);
|
||||
|
||||
IEnumerable<PaymentInfo> GetPayments(int tenantId);
|
||||
|
||||
Uri GetShoppingUri(int? tenant, int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null, string quantity = null);
|
||||
|
||||
IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds);
|
||||
|
||||
string GetButton(int tariffId, string partnerId);
|
||||
|
||||
void SaveButton(int tariffId, string partnerId, string buttonUrl);
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ServiceModel;
|
||||
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
namespace ASC.Core.Billing
|
||||
{
|
||||
[ServiceContract]
|
||||
public interface ITariffSyncService
|
||||
{
|
||||
[OperationContract]
|
||||
IEnumerable<TenantQuota> GetTariffs(int version, string key);
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace ASC.Core.Billing
|
||||
{
|
||||
public class Invoice
|
||||
{
|
||||
public string Sale
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string Refund
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
@ -229,6 +229,8 @@ namespace ASC.Core.Billing
|
||||
CountPortals = license.PortalCount,
|
||||
DiscEncryption = true,
|
||||
PrivacyRoom = true,
|
||||
Restore = true,
|
||||
ContentSearch = true
|
||||
};
|
||||
|
||||
if (defaultQuota.Name != "overdue" && !defaultQuota.Trial)
|
||||
|
@ -48,5 +48,17 @@ namespace ASC.Core.Billing
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int PaymentStatus
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int Quantity
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,34 +35,28 @@ namespace ASC.Core.Billing
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
public string PaymentType { get; set; }
|
||||
|
||||
public double ExchangeRate { get; set; }
|
||||
|
||||
public double GrossSum { get; set; }
|
||||
public int PaymentSystemId { get; set; }
|
||||
|
||||
public string CartId { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string FName { get; set; }
|
||||
|
||||
public string LName { get; set; }
|
||||
|
||||
public string Email { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
public DateTime PaymentDate { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
public Decimal Price { get; set; }
|
||||
|
||||
public string Currency { get; set; }
|
||||
public string PaymentCurrency { get; set; }
|
||||
|
||||
public string Method { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
|
||||
public int QuotaId { get; set; }
|
||||
|
||||
public string ProductId { get; set; }
|
||||
public string ProductRef { get; set; }
|
||||
|
||||
public string TenantID { get; set; }
|
||||
|
||||
public string Country { get; set; }
|
||||
|
||||
public decimal DiscountSum { get; set; }
|
||||
public string CustomerId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -47,8 +47,9 @@ namespace ASC.Core.Billing
|
||||
|
||||
public bool Autorenewal { get; set; }
|
||||
|
||||
public bool Prolongable { get; set; }
|
||||
|
||||
public bool Prolongable { get; set; }
|
||||
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public static Tariff CreateDefault()
|
||||
{
|
||||
@ -59,6 +60,7 @@ namespace ASC.Core.Billing
|
||||
DueDate = DateTime.MaxValue,
|
||||
DelayDueDate = DateTime.MaxValue,
|
||||
LicenseDate = DateTime.MaxValue,
|
||||
Quantity = 1
|
||||
};
|
||||
}
|
||||
|
||||
@ -71,6 +73,14 @@ namespace ASC.Core.Billing
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Tariff t && t.QuotaId == QuotaId;
|
||||
}
|
||||
|
||||
public bool EqualsByParams(Tariff t)
|
||||
{
|
||||
return t != null
|
||||
&& t.QuotaId == QuotaId
|
||||
&& t.DueDate == DueDate
|
||||
&& t.Quantity == Quantity;
|
||||
}
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
@ -37,7 +38,8 @@ using ASC.Common.Logging;
|
||||
using ASC.Core.Caching;
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
using ASC.Core.Users;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -57,7 +59,7 @@ namespace ASC.Core.Billing
|
||||
{
|
||||
Cache.Remove(TariffService.GetTariffCacheKey(i.TenantId));
|
||||
Cache.Remove(TariffService.GetBillingUrlCacheKey(i.TenantId));
|
||||
Cache.Remove(TariffService.GetBillingPaymentCacheKey(i.TenantId, DateTime.MinValue, DateTime.MaxValue)); // clear all payments
|
||||
Cache.Remove(TariffService.GetBillingPaymentCacheKey(i.TenantId)); // clear all payments
|
||||
}, CacheNotifyAction.Remove);
|
||||
|
||||
//TODO: Change code of WCF -> not supported in .NET standard/.Net Core
|
||||
@ -143,8 +145,6 @@ namespace ASC.Core.Billing
|
||||
private static readonly TimeSpan DEFAULT_CACHE_EXPIRATION = TimeSpan.FromMinutes(5);
|
||||
private static readonly TimeSpan STANDALONE_CACHE_EXPIRATION = TimeSpan.FromMinutes(15);
|
||||
|
||||
private readonly static bool billingConfigured = false;
|
||||
|
||||
internal ICache Cache { get; set; }
|
||||
internal ICacheNotify<TariffCacheItem> Notify { get; set; }
|
||||
internal ILog Log { get; set; }
|
||||
@ -161,6 +161,10 @@ namespace ASC.Core.Billing
|
||||
internal Lazy<CoreDbContext> LazyCoreDbContext { get; set; }
|
||||
internal TariffServiceStorage TariffServiceStorage { get; set; }
|
||||
internal IOptionsMonitor<ILog> Options { get; set; }
|
||||
public BillingClient BillingClient { get; }
|
||||
|
||||
public readonly int ACTIVE_USERS_MIN;
|
||||
public readonly int ACTIVE_USERS_MAX;
|
||||
|
||||
public TariffService()
|
||||
{
|
||||
@ -175,7 +179,9 @@ namespace ASC.Core.Billing
|
||||
IConfiguration configuration,
|
||||
DbContextManager<CoreDbContext> coreDbContextManager,
|
||||
TariffServiceStorage tariffServiceStorage,
|
||||
IOptionsMonitor<ILog> options)
|
||||
IOptionsMonitor<ILog> options,
|
||||
Constants constants,
|
||||
BillingClient billingClient)
|
||||
: this()
|
||||
|
||||
{
|
||||
@ -185,7 +191,8 @@ namespace ASC.Core.Billing
|
||||
CoreSettings = coreSettings;
|
||||
Configuration = configuration;
|
||||
TariffServiceStorage = tariffServiceStorage;
|
||||
Options = options;
|
||||
Options = options;
|
||||
BillingClient = billingClient;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
Test = configuration["core:payment:test"] == "true";
|
||||
int.TryParse(configuration["core:payment:delay"], out var paymentDelay);
|
||||
@ -194,7 +201,16 @@ namespace ASC.Core.Billing
|
||||
|
||||
Cache = TariffServiceStorage.Cache;
|
||||
Notify = TariffServiceStorage.Notify;
|
||||
LazyCoreDbContext = new Lazy<CoreDbContext>(() => coreDbContextManager.Value);
|
||||
LazyCoreDbContext = new Lazy<CoreDbContext>(() => coreDbContextManager.Value);
|
||||
var range = (Configuration["core.payment-user-range"] ?? "").Split('-');
|
||||
if (!int.TryParse(range[0], out ACTIVE_USERS_MIN))
|
||||
{
|
||||
ACTIVE_USERS_MIN = 0;
|
||||
}
|
||||
if (range.Length < 2 || !int.TryParse(range[1], out ACTIVE_USERS_MAX))
|
||||
{
|
||||
ACTIVE_USERS_MAX = constants.MaxEveryoneCount;
|
||||
}
|
||||
}
|
||||
|
||||
public Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true)
|
||||
@ -207,46 +223,50 @@ namespace ASC.Core.Billing
|
||||
var tariff = Cache.Get<Tariff>(key);
|
||||
if (tariff == null)
|
||||
{
|
||||
tariff = Tariff.CreateDefault();
|
||||
|
||||
var cached = GetBillingInfo(tenantId);
|
||||
if (cached != null)
|
||||
{
|
||||
tariff.QuotaId = cached.Item1;
|
||||
tariff.DueDate = cached.Item2;
|
||||
}
|
||||
|
||||
tariff = GetBillingInfo(tenantId);
|
||||
tariff = CalculateTariff(tenantId, tariff);
|
||||
Cache.Insert(key, tariff, DateTime.UtcNow.Add(GetCacheExpiration()));
|
||||
|
||||
if (billingConfigured && withRequestToPaymentSystem)
|
||||
if (BillingClient.Configured && withRequestToPaymentSystem)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = GetBillingClient();
|
||||
var p = client.GetLastPayment(GetPortalId(tenantId));
|
||||
var quota = QuotaService.GetTenantQuotas().SingleOrDefault(q => q.AvangateId == p.ProductId);
|
||||
var client = GetBillingClient();
|
||||
var lastPayment = client.GetLastPayment(GetPortalId(tenantId));
|
||||
|
||||
var quota = QuotaService.GetTenantQuotas().SingleOrDefault(q => q.AvangateId == lastPayment.ProductId);
|
||||
if (quota == null)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Quota with id {0} not found for portal {1}.", p.ProductId, GetPortalId(tenantId)));
|
||||
throw new InvalidOperationException(string.Format("Quota with id {0} not found for portal {1}.", lastPayment.ProductId, GetPortalId(tenantId)));
|
||||
}
|
||||
|
||||
var asynctariff = Tariff.CreateDefault();
|
||||
asynctariff.QuotaId = quota.Id;
|
||||
asynctariff.Autorenewal = p.Autorenewal;
|
||||
asynctariff.DueDate = 9999 <= p.EndDate.Year ? DateTime.MaxValue : p.EndDate;
|
||||
asynctariff.Autorenewal = lastPayment.Autorenewal;
|
||||
asynctariff.DueDate = 9999 <= lastPayment.EndDate.Year ? DateTime.MaxValue : lastPayment.EndDate;
|
||||
|
||||
if (SaveBillingInfo(tenantId, Tuple.Create(asynctariff.QuotaId, asynctariff.DueDate), false))
|
||||
if (quota.ActiveUsers == -1
|
||||
&& lastPayment.Quantity < ACTIVE_USERS_MIN)
|
||||
{
|
||||
throw new BillingException(string.Format("The portal {0} is paid for {1} users", tenantId, lastPayment.Quantity));
|
||||
}
|
||||
asynctariff.Quantity = lastPayment.Quantity;
|
||||
|
||||
if (SaveBillingInfo(tenantId, asynctariff, false))
|
||||
{
|
||||
asynctariff = CalculateTariff(tenantId, asynctariff);
|
||||
ClearCache(tenantId);
|
||||
Cache.Insert(key, asynctariff, DateTime.UtcNow.Add(GetCacheExpiration()));
|
||||
}
|
||||
}
|
||||
catch (BillingNotFoundException)
|
||||
{
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
LogError(error);
|
||||
LogError(error, tenantId.ToString());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -264,7 +284,7 @@ namespace ASC.Core.Billing
|
||||
|
||||
var q = QuotaService.GetTenantQuota(tariff.QuotaId);
|
||||
if (q == null) return;
|
||||
SaveBillingInfo(tenantId, Tuple.Create(tariff.QuotaId, tariff.DueDate));
|
||||
SaveBillingInfo(tenantId, tariff);
|
||||
if (q.Trial)
|
||||
{
|
||||
// reset trial date
|
||||
@ -289,9 +309,9 @@ namespace ASC.Core.Billing
|
||||
return string.Format("{0}:{1}", tenantId, "billing:urls");
|
||||
}
|
||||
|
||||
internal static string GetBillingPaymentCacheKey(int tenantId, DateTime from, DateTime to)
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}-{3}", tenantId, "billing:payments", from.ToString("yyyyMMddHHmmss"), to.ToString("yyyyMMddHHmmss"));
|
||||
internal static string GetBillingPaymentCacheKey(int tenantId)
|
||||
{
|
||||
return string.Format("{0}:{1}", tenantId, "billing:payments");
|
||||
}
|
||||
|
||||
|
||||
@ -299,45 +319,43 @@ namespace ASC.Core.Billing
|
||||
{
|
||||
Notify.Publish(new TariffCacheItem { TenantId = tenantId }, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
public IEnumerable<PaymentInfo> GetPayments(int tenantId)
|
||||
{
|
||||
var key = GetBillingPaymentCacheKey(tenantId);
|
||||
var payments = Cache.Get<List<PaymentInfo>>(key);
|
||||
if (payments == null)
|
||||
{
|
||||
payments = new List<PaymentInfo>();
|
||||
if (BillingClient.Configured)
|
||||
{
|
||||
try
|
||||
{
|
||||
var quotas = QuotaService.GetTenantQuotas();
|
||||
var client = GetBillingClient();
|
||||
foreach (var pi in client.GetPayments(GetPortalId(tenantId)))
|
||||
{
|
||||
var quota = quotas.SingleOrDefault(q => q.AvangateId == pi.ProductRef);
|
||||
if (quota != null)
|
||||
{
|
||||
pi.QuotaId = quota.Id;
|
||||
}
|
||||
payments.Add(pi);
|
||||
}
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
LogError(error, tenantId.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
Cache.Insert(key, payments, DateTime.UtcNow.Add(TimeSpan.FromMinutes(10)));
|
||||
}
|
||||
|
||||
return payments;
|
||||
}
|
||||
|
||||
public IEnumerable<PaymentInfo> GetPayments(int tenantId, DateTime from, DateTime to)
|
||||
{
|
||||
from = from.Date;
|
||||
to = to.Date.AddTicks(TimeSpan.TicksPerDay - 1);
|
||||
var key = GetBillingPaymentCacheKey(tenantId, from, to);
|
||||
var payments = Cache.Get<List<PaymentInfo>>(key);
|
||||
if (payments == null)
|
||||
{
|
||||
payments = new List<PaymentInfo>();
|
||||
if (billingConfigured)
|
||||
{
|
||||
try
|
||||
{
|
||||
var quotas = QuotaService.GetTenantQuotas();
|
||||
using var client = GetBillingClient();
|
||||
foreach (var pi in client.GetPayments(GetPortalId(tenantId), from, to))
|
||||
{
|
||||
var quota = quotas.SingleOrDefault(q => q.AvangateId == pi.ProductId);
|
||||
if (quota != null)
|
||||
{
|
||||
pi.QuotaId = quota.Id;
|
||||
}
|
||||
payments.Add(pi);
|
||||
}
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
LogError(error);
|
||||
}
|
||||
}
|
||||
|
||||
Cache.Insert(key, payments, DateTime.UtcNow.Add(TimeSpan.FromMinutes(10)));
|
||||
}
|
||||
|
||||
return payments;
|
||||
}
|
||||
|
||||
public Uri GetShoppingUri(int? tenant, int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null)
|
||||
public Uri GetShoppingUri(int? tenant, int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
{
|
||||
var quota = QuotaService.GetTenantQuota(quotaId);
|
||||
if (quota == null) return null;
|
||||
@ -349,19 +367,27 @@ namespace ASC.Core.Billing
|
||||
if (!(Cache.Get<Dictionary<string, Tuple<Uri, Uri>>>(key) is IDictionary<string, Tuple<Uri, Uri>> urls))
|
||||
{
|
||||
urls = new Dictionary<string, Tuple<Uri, Uri>>();
|
||||
if (billingConfigured)
|
||||
if (BillingClient.Configured)
|
||||
{
|
||||
try
|
||||
{
|
||||
var products = QuotaService.GetTenantQuotas()
|
||||
.Where(q => !string.IsNullOrEmpty(q.AvangateId) && q.Visible == quota.Visible)
|
||||
.Select(q => q.AvangateId)
|
||||
.ToArray();
|
||||
|
||||
using var client = GetBillingClient();
|
||||
urls = tenant.HasValue ?
|
||||
client.GetPaymentUrls(GetPortalId(tenant.Value), products, GetAffiliateId(tenant.Value), GetCampaign(tenant.Value), "__Currency__", "__Language__", "__CustomerID__") :
|
||||
client.GetPaymentUrls(null, products, !string.IsNullOrEmpty(affiliateId) ? affiliateId : null, null, "__Currency__", "__Language__", "__CustomerID__");
|
||||
.ToArray();
|
||||
|
||||
var client = GetBillingClient();
|
||||
urls =
|
||||
client.GetPaymentUrls(
|
||||
tenant.HasValue ? GetPortalId(tenant.Value) : null,
|
||||
products,
|
||||
tenant.HasValue ? GetAffiliateId(tenant.Value) : affiliateId,
|
||||
tenant.HasValue ? GetCampaign(tenant.Value) : null,
|
||||
!string.IsNullOrEmpty(currency) ? "__Currency__" : null,
|
||||
!string.IsNullOrEmpty(language) ? "__Language__" : null,
|
||||
!string.IsNullOrEmpty(customerId) ? "__CustomerID__" : null,
|
||||
!string.IsNullOrEmpty(quantity) ? "__Quantity__" : null
|
||||
);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
@ -373,71 +399,60 @@ namespace ASC.Core.Billing
|
||||
|
||||
ResetCacheExpiration();
|
||||
|
||||
if (!string.IsNullOrEmpty(quota.AvangateId) && urls.TryGetValue(quota.AvangateId, out var tuple))
|
||||
{
|
||||
var result = tuple.Item2;
|
||||
if (!string.IsNullOrEmpty(quota.AvangateId) && urls.TryGetValue(quota.AvangateId, out var tuple))
|
||||
{
|
||||
var result = tuple.Item2;
|
||||
|
||||
var tariff = tenant.HasValue ? GetTariff(tenant.Value) : null;
|
||||
if (result == null || tariff == null || tariff.QuotaId == quotaId || tariff.State >= TariffState.Delay)
|
||||
{
|
||||
result = tuple.Item1;
|
||||
}
|
||||
|
||||
result = new Uri(result.ToString()
|
||||
.Replace("__Currency__", currency ?? "")
|
||||
.Replace("__Language__", (language ?? "").ToLower())
|
||||
.Replace("__CustomerID__", customerId ?? ""));
|
||||
return result;
|
||||
if (result == null)
|
||||
{
|
||||
result = tuple.Item1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tariff = tenant.HasValue ? GetTariff(tenant.Value) : null;
|
||||
if (tariff == null || tariff.QuotaId == quotaId || tariff.State >= TariffState.Delay)
|
||||
{
|
||||
result = tuple.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) return null;
|
||||
|
||||
result = new Uri(result.ToString()
|
||||
.Replace("__Currency__", HttpUtility.UrlEncode(currency ?? ""))
|
||||
.Replace("__Language__", HttpUtility.UrlEncode((language ?? "").ToLower()))
|
||||
.Replace("__CustomerID__", HttpUtility.UrlEncode(customerId ?? ""))
|
||||
.Replace("__Quantity__", HttpUtility.UrlEncode(quantity ?? "")));
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IDictionary<string, IEnumerable<Tuple<string, decimal>>> GetProductPriceInfo(params string[] productIds)
|
||||
{
|
||||
if (productIds == null)
|
||||
{
|
||||
throw new ArgumentNullException("productIds");
|
||||
}
|
||||
try
|
||||
{
|
||||
var key = "biling-prices" + string.Join(",", productIds);
|
||||
var result = Cache.Get<IDictionary<string, IEnumerable<Tuple<string, decimal>>>>(key);
|
||||
if (result == null)
|
||||
{
|
||||
using (var client = GetBillingClient())
|
||||
{
|
||||
result = client.GetProductPriceInfo(productIds);
|
||||
}
|
||||
Cache.Insert(key, result, DateTime.Now.AddHours(1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
LogError(error);
|
||||
return productIds
|
||||
.Select(p => new { ProductId = p, Prices = Enumerable.Empty<Tuple<string, decimal>>() })
|
||||
.ToDictionary(e => e.ProductId, e => e.Prices);
|
||||
}
|
||||
}
|
||||
|
||||
public Invoice GetInvoice(string paymentId)
|
||||
{
|
||||
var result = new Invoice();
|
||||
|
||||
if (billingConfigured)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = GetBillingClient();
|
||||
result = client.GetInvoice(paymentId);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
LogError(error);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds)
|
||||
{
|
||||
if (productIds == null)
|
||||
{
|
||||
throw new ArgumentNullException("productIds");
|
||||
}
|
||||
try
|
||||
{
|
||||
var key = "biling-prices" + string.Join(",", productIds);
|
||||
var result = Cache.Get<IDictionary<string, Dictionary<string, decimal>>>(key);
|
||||
if (result == null)
|
||||
{
|
||||
var client = GetBillingClient();
|
||||
result = client.GetProductPriceInfo(productIds);
|
||||
Cache.Insert(key, result, DateTime.Now.AddHours(1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
LogError(error);
|
||||
return productIds
|
||||
.Select(p => new { ProductId = p, Prices = new Dictionary<string, decimal>() })
|
||||
.ToDictionary(e => e.ProductId, e => e.Prices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -463,34 +478,42 @@ namespace ASC.Core.Billing
|
||||
}
|
||||
|
||||
|
||||
private Tuple<int, DateTime> GetBillingInfo(int tenant)
|
||||
private Tariff GetBillingInfo(int tenant)
|
||||
{
|
||||
var r = CoreDbContext.Tariffs
|
||||
.Where(r => r.Tenant == tenant)
|
||||
.OrderByDescending(r => r.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
return r != null ? Tuple.Create(r.Tariff, r.Stamp.Year < 9999 ? r.Stamp : DateTime.MaxValue) : null;
|
||||
.SingleOrDefault();
|
||||
|
||||
if (r == null) return Tariff.CreateDefault();
|
||||
|
||||
var tariff = Tariff.CreateDefault();
|
||||
tariff.QuotaId = r.Tariff;
|
||||
tariff.DueDate = r.Stamp.Year < 9999 ? r.Stamp : DateTime.MaxValue;
|
||||
tariff.Quantity = r.Quantity;
|
||||
return tariff;
|
||||
}
|
||||
|
||||
private bool SaveBillingInfo(int tenant, Tuple<int, DateTime> bi, bool renewal = true)
|
||||
private bool SaveBillingInfo(int tenant, Tariff tariffInfo, bool renewal = true)
|
||||
{
|
||||
var inserted = false;
|
||||
if (!Equals(bi, GetBillingInfo(tenant)))
|
||||
var inserted = false;
|
||||
var currentTariff = GetBillingInfo(tenant);
|
||||
if (!tariffInfo.EqualsByParams(currentTariff))
|
||||
{
|
||||
using var tx = CoreDbContext.Database.BeginTransaction();
|
||||
|
||||
// last record is not the same
|
||||
var count = CoreDbContext.Tariffs
|
||||
.Count(r => r.Tenant == tenant && r.Tariff == bi.Item1 && r.Stamp == bi.Item2);
|
||||
|
||||
if (bi.Item2 == DateTime.MaxValue || renewal || count == 0)
|
||||
.Count(r => r.Tenant == tenant && r.Tariff == tariffInfo.QuotaId && r.Stamp == tariffInfo.DueDate && r.Quantity == tariffInfo.Quantity);
|
||||
|
||||
if (tariffInfo.DueDate == DateTime.MaxValue || renewal || count == 0)
|
||||
{
|
||||
var efTariff = new DbTariff
|
||||
{
|
||||
Tenant = tenant,
|
||||
Tariff = bi.Item1,
|
||||
Stamp = bi.Item2,
|
||||
Tariff = tariffInfo.QuotaId,
|
||||
Stamp = tariffInfo.DueDate,
|
||||
Quantity = tariffInfo.Quantity,
|
||||
CreateOn = DateTime.UtcNow
|
||||
};
|
||||
|
||||
@ -617,7 +640,7 @@ namespace ASC.Core.Billing
|
||||
{
|
||||
try
|
||||
{
|
||||
return new BillingClient(Test, Configuration, Options);
|
||||
return new BillingClient(Test, Configuration);
|
||||
}
|
||||
catch (InvalidOperationException ioe)
|
||||
{
|
||||
@ -665,27 +688,28 @@ namespace ASC.Core.Billing
|
||||
}
|
||||
}
|
||||
|
||||
private void LogError(Exception error)
|
||||
{
|
||||
if (error is BillingNotFoundException)
|
||||
{
|
||||
Log.DebugFormat("Payment not found: {0}", error.Message);
|
||||
}
|
||||
else if (error is BillingNotConfiguredException)
|
||||
{
|
||||
Log.DebugFormat("Billing not configured: {0}", error.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.Error(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error(error.Message);
|
||||
}
|
||||
}
|
||||
private void LogError(Exception error, string tenantId = null)
|
||||
{
|
||||
if (error is BillingNotFoundException)
|
||||
{
|
||||
Log.DebugFormat("Payment tenant {0} not found: {1}", tenantId, error.Message);
|
||||
}
|
||||
else if (error is BillingNotConfiguredException)
|
||||
{
|
||||
Log.DebugFormat("Billing tenant {0} not configured: {1}", tenantId, error.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.Error("Billing tenant " + tenantId);
|
||||
Log.Error(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.ErrorFormat("Billing tenant {0}: {1}", tenantId, error.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ASC.Common.Module;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
namespace ASC.Core.Billing
|
||||
{
|
||||
public class TariffSyncClient : BaseWcfClient<ITariffSyncService>, ITariffSyncService
|
||||
{
|
||||
public IEnumerable<TenantQuota> GetTariffs(int version, string key)
|
||||
{
|
||||
return Channel.GetTariffs(version, key);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Common.Module;
|
||||
using ASC.Common.Utils;
|
||||
using ASC.Core.Data;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Billing
|
||||
{
|
||||
class TariffSyncService : ITariffSyncService, IServiceController
|
||||
{
|
||||
private readonly ILog log;
|
||||
private readonly TariffSyncServiceSection config;
|
||||
private readonly IDictionary<int, IEnumerable<TenantQuota>> quotaServices = new Dictionary<int, IEnumerable<TenantQuota>>();
|
||||
private Timer timer;
|
||||
|
||||
|
||||
public TariffSyncService(
|
||||
IServiceProvider serviceProvider,
|
||||
ConfigurationExtension configuration,
|
||||
DbQuotaService dbQuotaService,
|
||||
IOptionsMonitor<ILog> options)
|
||||
{
|
||||
config = TariffSyncServiceSection.GetSection();
|
||||
ServiceProvider = serviceProvider;
|
||||
Configuration = configuration;
|
||||
DbQuotaService = dbQuotaService;
|
||||
log = options.CurrentValue;
|
||||
}
|
||||
|
||||
|
||||
// server part of service
|
||||
public IEnumerable<TenantQuota> GetTariffs(int version, string key)
|
||||
{
|
||||
lock (quotaServices)
|
||||
{
|
||||
if (!quotaServices.ContainsKey(version))
|
||||
{
|
||||
var cs = Configuration.GetConnectionStrings(config.ConnectionStringName + version) ??
|
||||
Configuration.GetConnectionStrings(config.ConnectionStringName);
|
||||
quotaServices[version] = DbQuotaService.GetTenantQuotas();
|
||||
}
|
||||
return quotaServices[version];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// client part of service
|
||||
public string ServiceName
|
||||
{
|
||||
get { return "Tariffs synchronizer"; }
|
||||
}
|
||||
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
private ConfigurationExtension Configuration { get; }
|
||||
private DbQuotaService DbQuotaService { get; }
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (timer == null)
|
||||
{
|
||||
timer = new Timer(Sync, null, TimeSpan.Zero, config.Period);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (timer != null)
|
||||
{
|
||||
timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
timer.Dispose();
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void Sync(object _)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var tariffSync = scope.ServiceProvider.GetService<TariffSync>();
|
||||
tariffSync.Sync();
|
||||
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
log.Error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TariffSync
|
||||
{
|
||||
public TariffSync(TenantManager tenantManager, CoreSettings coreSettings, DbQuotaService dbQuotaService)
|
||||
{
|
||||
TenantManager = tenantManager;
|
||||
CoreSettings = coreSettings;
|
||||
DbQuotaService = dbQuotaService;
|
||||
}
|
||||
|
||||
private TenantManager TenantManager { get; }
|
||||
private CoreSettings CoreSettings { get; }
|
||||
private DbQuotaService DbQuotaService { get; }
|
||||
|
||||
public void Sync()
|
||||
{
|
||||
var tenant = TenantManager.GetTenants(false).OrderByDescending(t => t.Version).FirstOrDefault();
|
||||
if (tenant != null)
|
||||
{
|
||||
using var wcfClient = new TariffSyncClient();
|
||||
var quotaService = DbQuotaService;
|
||||
|
||||
var oldtariffs = quotaService.GetTenantQuotas().ToDictionary(t => t.Id);
|
||||
// save new
|
||||
foreach (var tariff in wcfClient.GetTariffs(tenant.Version, CoreSettings.GetKey(tenant.TenantId)))
|
||||
{
|
||||
quotaService.SaveTenantQuota(tariff);
|
||||
oldtariffs.Remove(tariff.Id);
|
||||
}
|
||||
|
||||
// remove old
|
||||
foreach (var tariff in oldtariffs.Values)
|
||||
{
|
||||
tariff.Visible = false;
|
||||
quotaService.SaveTenantQuota(tariff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace ASC.Core.Billing
|
||||
{
|
||||
class TariffSyncServiceSection : ConfigurationSection
|
||||
{
|
||||
[ConfigurationProperty("period", DefaultValue = "4:0:0")]
|
||||
public TimeSpan Period
|
||||
{
|
||||
get { return (TimeSpan)this["period"]; }
|
||||
set { this["period"] = value; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("connectionStringName", DefaultValue = "core")]
|
||||
public string ConnectionStringName
|
||||
{
|
||||
get { return (string)this["connectionStringName"]; }
|
||||
set { this["connectionStringName"] = value; }
|
||||
}
|
||||
|
||||
public static TariffSyncServiceSection GetSection()
|
||||
{
|
||||
return (TariffSyncServiceSection)ConfigurationManager.GetSection("tariffs") ?? new TariffSyncServiceSection();
|
||||
}
|
||||
}
|
||||
}
|
@ -82,37 +82,23 @@ namespace ASC.Core
|
||||
|
||||
public IEnumerable<PaymentInfo> GetTariffPayments(int tenant)
|
||||
{
|
||||
return GetTariffPayments(tenant, DateTime.MinValue, DateTime.MaxValue);
|
||||
}
|
||||
|
||||
public IEnumerable<PaymentInfo> GetTariffPayments(int tenant, DateTime from, DateTime to)
|
||||
{
|
||||
return tariffService.GetPayments(tenant, from, to);
|
||||
}
|
||||
|
||||
public Invoice GetPaymentInvoice(string paymentId)
|
||||
{
|
||||
return tariffService.GetInvoice(paymentId);
|
||||
return tariffService.GetPayments(tenant);
|
||||
}
|
||||
|
||||
public IDictionary<string, IEnumerable<Tuple<string, decimal>>> GetProductPriceInfo(params string[] productIds)
|
||||
public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds)
|
||||
{
|
||||
return tariffService.GetProductPriceInfo(productIds);
|
||||
}
|
||||
|
||||
public Uri GetShoppingUri(int tenant, int quotaId, string currency = null, string language = null, string customerId = null)
|
||||
|
||||
public Uri GetShoppingUri(int quotaId, bool forCurrentTenant = true, string affiliateId = null, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
{
|
||||
return tariffService.GetShoppingUri(tenant, quotaId, null, currency, language, customerId);
|
||||
return tariffService.GetShoppingUri(forCurrentTenant ? TenantManager.GetCurrentTenant().TenantId : (int?)null, quotaId, affiliateId, currency, language, customerId, quantity);
|
||||
}
|
||||
|
||||
public Uri GetShoppingUri(int quotaId, bool forCurrentTenant = true, string affiliateId = null, string currency = null, string language = null, string customerId = null)
|
||||
public Uri GetShoppingUri(int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null, string quantity = null)
|
||||
{
|
||||
return tariffService.GetShoppingUri(forCurrentTenant ? TenantManager.GetCurrentTenant().TenantId : (int?)null, quotaId, affiliateId, currency, language, customerId);
|
||||
}
|
||||
|
||||
public Uri GetShoppingUri(int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null)
|
||||
{
|
||||
return tariffService.GetShoppingUri(null, quotaId, affiliateId, currency, language, customerId);
|
||||
return tariffService.GetShoppingUri(null, quotaId, affiliateId, currency, language, customerId, quantity);
|
||||
}
|
||||
|
||||
public void ActivateKey(string key)
|
||||
|
@ -312,23 +312,31 @@ namespace ASC.Core
|
||||
{
|
||||
return QuotaService.GetTenantQuotas().Where(q => q.Id < 0 && (all || q.Visible)).OrderByDescending(q => q.Id).ToList();
|
||||
}
|
||||
|
||||
public TenantQuota GetTenantQuota(int tenant)
|
||||
{
|
||||
var defaultQuota = QuotaService.GetTenantQuota(tenant) ?? QuotaService.GetTenantQuota(Tenant.DEFAULT_TENANT) ?? TenantQuota.Default;
|
||||
if (defaultQuota.Id != tenant && TariffService != null)
|
||||
{
|
||||
var tariff = TariffService.GetTariff(tenant);
|
||||
var currentQuota = QuotaService.GetTenantQuota(tariff.QuotaId);
|
||||
if (currentQuota != null)
|
||||
{
|
||||
currentQuota = (TenantQuota)currentQuota.Clone();
|
||||
|
||||
if (currentQuota.ActiveUsers == -1)
|
||||
{
|
||||
currentQuota.ActiveUsers = tariff.Quantity;
|
||||
currentQuota.MaxTotalSize *= currentQuota.ActiveUsers;
|
||||
}
|
||||
|
||||
return currentQuota;
|
||||
}
|
||||
}
|
||||
return defaultQuota;
|
||||
}
|
||||
|
||||
public TenantQuota GetTenantQuota(int tenant)
|
||||
{
|
||||
// если в tenants_quota есть строка, с данным идентификатором портала, то в качестве квоты берется именно она
|
||||
var q = QuotaService.GetTenantQuota(tenant) ?? QuotaService.GetTenantQuota(Tenant.DEFAULT_TENANT) ?? TenantQuota.Default;
|
||||
if (q.Id != tenant && TariffService != null)
|
||||
{
|
||||
var tariffQuota = QuotaService.GetTenantQuota(TariffService.GetTariff(tenant).QuotaId);
|
||||
if (tariffQuota != null)
|
||||
{
|
||||
return tariffQuota;
|
||||
}
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
public IDictionary<string, IEnumerable<Tuple<string, decimal>>> GetProductPriceInfo(bool all = true)
|
||||
public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(bool all = true)
|
||||
{
|
||||
var productIds = GetTenantQuotas(all)
|
||||
.Select(p => p.AvangateId)
|
||||
|
@ -66,7 +66,7 @@ namespace ASC.Core
|
||||
private TenantManager TenantManager { get; }
|
||||
private PermissionContext PermissionContext { get; }
|
||||
private UserManagerConstants UserManagerConstants { get; }
|
||||
public CoreBaseSettings CoreBaseSettings { get; }
|
||||
private CoreBaseSettings CoreBaseSettings { get; }
|
||||
private Constants Constants { get; }
|
||||
|
||||
private Tenant tenant;
|
||||
@ -310,7 +310,52 @@ namespace ASC.Core
|
||||
var newUser = UserService.SaveUser(Tenant.TenantId, u);
|
||||
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
|
||||
public UserInfo SaveUserInfo(UserInfo u, bool isVisitor = false)
|
||||
{
|
||||
if (IsSystemUser(u.ID)) return SystemUsers[u.ID];
|
||||
if (u.ID == Guid.Empty) PermissionContext.DemandPermissions(Constants.Action_AddRemoveUser);
|
||||
else PermissionContext.DemandPermissions(new UserSecurityProvider(u.ID), Constants.Action_EditUser);
|
||||
|
||||
if (!CoreBaseSettings.Personal)
|
||||
{
|
||||
if (Constants.MaxEveryoneCount <= GetUsersByGroup(Constants.GroupEveryone.ID).Length)
|
||||
{
|
||||
throw new TenantQuotaException("Maximum number of users exceeded");
|
||||
}
|
||||
|
||||
if (u.Status == EmployeeStatus.Active)
|
||||
{
|
||||
if (isVisitor)
|
||||
{
|
||||
var maxUsers = TenantManager.GetTenantQuota(TenantManager.GetCurrentTenant().TenantId).ActiveUsers;
|
||||
var visitors = TenantManager.GetTenantQuota(TenantManager.GetCurrentTenant().TenantId).Free ? 0 : Constants.CoefficientOfVisitors;
|
||||
if (!CoreBaseSettings.Standalone && GetUsersByGroup(Constants.GroupVisitor.ID).Length > visitors * maxUsers)
|
||||
{
|
||||
throw new TenantQuotaException("Maximum number of visitors exceeded");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var q = TenantManager.GetTenantQuota(TenantManager.GetCurrentTenant().TenantId);
|
||||
if (q.ActiveUsers < GetUsersByGroup(Constants.GroupUser.ID).Length)
|
||||
{
|
||||
throw new TenantQuotaException(string.Format("Exceeds the maximum active users ({0})", q.ActiveUsers));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (u.Status == EmployeeStatus.Terminated && u.ID == TenantManager.GetCurrentTenant().OwnerId)
|
||||
{
|
||||
throw new InvalidOperationException("Can not disable tenant owner.");
|
||||
}
|
||||
|
||||
var newUser = UserService.SaveUser(TenantManager.GetCurrentTenant().TenantId, u);
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
public void DeleteUser(Guid id)
|
||||
{
|
||||
|
@ -224,7 +224,7 @@ namespace ASC.Core.Data
|
||||
var passwordHashs = usersQuery.Select(r => GetPasswordHash(r, passwordHash)).ToList();
|
||||
|
||||
q = query()
|
||||
.Where(r => passwordHashs.Any(p => r.UserSecurity.PwdHash == p));
|
||||
.Where(r => passwordHashs.Any(p => r.UserSecurity.PwdHash == p) && r.DbTenant.Status == TenantStatus.Active);
|
||||
|
||||
//new password
|
||||
result = result.Concat(q.Select(FromTenantUserToTenant)).ToList();
|
||||
|
@ -54,6 +54,11 @@ namespace ASC.Core.Common.EF.Model
|
||||
new FilesConverts { Input = ".epub", Output = ".pdf" },
|
||||
new FilesConverts { Input = ".epub", Output = ".rtf" },
|
||||
new FilesConverts { Input = ".epub", Output = ".txt" },
|
||||
new FilesConverts { Input = ".fb2", Output = ".docx" },
|
||||
new FilesConverts { Input = ".fb2", Output = ".odt" },
|
||||
new FilesConverts { Input = ".fb2", Output = ".pdf" },
|
||||
new FilesConverts { Input = ".fb2", Output = ".rtf" },
|
||||
new FilesConverts { Input = ".fb2", Output = ".txt" },
|
||||
new FilesConverts { Input = ".fodp", Output = ".odp" },
|
||||
new FilesConverts { Input = ".fodp", Output = ".pdf" },
|
||||
new FilesConverts { Input = ".fodp", Output = ".pptx" },
|
||||
|
@ -1,4 +1,5 @@
|
||||
using ASC.Core.Common.EF.Model;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ASC.Core.Common.EF
|
||||
@ -29,7 +30,7 @@ namespace ASC.Core.Common.EF
|
||||
.Add(MySqlAddDbQuota, Provider.MySql)
|
||||
.Add(PgSqlAddDbQuota, Provider.Postgre)
|
||||
.HasData(
|
||||
new DbQuota { Tenant = -1, Name = "default", Description = null, MaxFileSize = 102400, MaxTotalSize = 10995116277760, ActiveUsers = 10000, Features = "docs,domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption", Price = decimal.Parse("0,00"), Price2 = decimal.Parse("0,00"), AvangateId = "0", Visible = false }
|
||||
new DbQuota { Tenant = -1, Name = "default", Description = null, MaxFileSize = 102400, MaxTotalSize = 10995116277760, ActiveUsers = 10000, Features = "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore", Price = decimal.Parse("0,00"), Price2 = decimal.Parse("0,00"), AvangateId = "0", Visible = false }
|
||||
);
|
||||
|
||||
return modelBuilder;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
using ASC.Core.Common.EF.Model;
|
||||
|
||||
@ -13,6 +12,7 @@ namespace ASC.Core.Common.EF
|
||||
public int Tenant { get; set; }
|
||||
public int Tariff { get; set; }
|
||||
public DateTime Stamp { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public string Comment { get; set; }
|
||||
public DateTime CreateOn { get; set; }
|
||||
}
|
||||
@ -48,6 +48,10 @@ namespace ASC.Core.Common.EF
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP")
|
||||
.ValueGeneratedOnAddOrUpdate();
|
||||
|
||||
entity.Property(e => e.Quantity)
|
||||
.HasColumnName("stamp")
|
||||
.HasColumnType("int");
|
||||
|
||||
entity.Property(e => e.Stamp)
|
||||
.HasColumnName("stamp")
|
||||
.HasColumnType("datetime");
|
||||
@ -79,6 +83,8 @@ namespace ASC.Core.Common.EF
|
||||
|
||||
entity.Property(e => e.Stamp).HasColumnName("stamp");
|
||||
|
||||
entity.Property(e => e.Quantity).HasColumnName("quantity");
|
||||
|
||||
entity.Property(e => e.Tariff).HasColumnName("tariff");
|
||||
|
||||
entity.Property(e => e.Tenant).HasColumnName("tenant");
|
||||
|
@ -676,7 +676,7 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
Tenant = -1,
|
||||
ActiveUsers = 10000,
|
||||
AvangateId = "0",
|
||||
Features = "docs,domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption",
|
||||
Features = "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore",
|
||||
MaxFileSize = 102400L,
|
||||
MaxTotalSize = 10995116277760L,
|
||||
Name = "default",
|
||||
@ -744,13 +744,16 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
|
||||
b.Property<DateTime>("Stamp")
|
||||
.HasColumnType("datetime")
|
||||
.HasColumnName("stamp");
|
||||
.HasColumnName("stamp");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("quantity");
|
||||
|
||||
b.Property<int>("Tariff")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("tariff");
|
||||
|
||||
|
||||
b.Property<int>("Tenant")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("tenant");
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
@ -92,7 +93,8 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
tenant = table.Column<int>(type: "int", nullable: false),
|
||||
tariff = table.Column<int>(type: "int", nullable: false),
|
||||
stamp = table.Column<DateTime>(type: "datetime", nullable: false),
|
||||
stamp = table.Column<DateTime>(type: "datetime", nullable: false),
|
||||
quantity = table.Column<int>(type: "int", nullable: false),
|
||||
tariff_key = table.Column<string>(type: "varchar(64)", nullable: true, collation: "utf8_general_ci")
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
comment = table.Column<string>(type: "varchar(255)", nullable: true, collation: "utf8_general_ci")
|
||||
@ -180,7 +182,7 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
migrationBuilder.InsertData(
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "active_users", "avangate_id", "description", "features", "max_file_size", "max_total_size", "name", "price", "price2", "visible" },
|
||||
values: new object[] { -1, 10000, "0", null, "docs,domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption", 102400L, 10995116277760L, "default", 0.00m, 0.00m, false });
|
||||
values: new object[] { -1, 10000, "0", null, "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore", 102400L, 10995116277760L, "default", 0.00m, 0.00m, false });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "last_modified",
|
||||
|
@ -674,7 +674,7 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
Tenant = -1,
|
||||
ActiveUsers = 10000,
|
||||
AvangateId = "0",
|
||||
Features = "docs,domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption",
|
||||
Features = "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore",
|
||||
MaxFileSize = 102400L,
|
||||
MaxTotalSize = 10995116277760L,
|
||||
Name = "default",
|
||||
@ -742,7 +742,11 @@ namespace ASC.Core.Common.Migrations.MySql.CoreDbContextMySql
|
||||
|
||||
b.Property<DateTime>("Stamp")
|
||||
.HasColumnType("datetime")
|
||||
.HasColumnName("stamp");
|
||||
.HasColumnName("stamp");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("quantity");
|
||||
|
||||
b.Property<int>("Tariff")
|
||||
.HasColumnType("int")
|
||||
|
@ -229,6 +229,31 @@ namespace ASC.Core.Common.Migrations.MySql.FilesDbContextMySql
|
||||
Output = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".docx"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".odt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".pdf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".rtf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fodp",
|
||||
Output = ".odp"
|
||||
|
@ -167,7 +167,12 @@ namespace ASC.Core.Common.Migrations.MySql.FilesDbContextMySql
|
||||
{ ".fodt", ".txt" },
|
||||
{ ".html", ".docx" },
|
||||
{ ".fods", ".xlsx" },
|
||||
{ ".xps", ".pdf" }
|
||||
{ ".xps", ".pdf" },
|
||||
{ ".fb2", ".docx" },
|
||||
{ ".fb2", ".odt" },
|
||||
{ ".fb2", ".pdf" },
|
||||
{ ".fb2", ".rtf" },
|
||||
{ ".fb2", ".txt" }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -227,6 +227,31 @@ namespace ASC.Core.Common.Migrations.MySql.FilesDbContextMySql
|
||||
Output = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".docx"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".odt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".pdf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".rtf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Output = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fodp",
|
||||
Output = ".odp"
|
||||
|
@ -730,7 +730,11 @@ namespace ASC.Core.Common.Migrations.Npgsql.CoreDbContextNpgsql
|
||||
|
||||
b.Property<DateTime>("Stamp")
|
||||
.HasColumnName("stamp")
|
||||
.HasColumnType("timestamp without time zone");
|
||||
.HasColumnType("timestamp without time zone");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("quantity");
|
||||
|
||||
b.Property<int>("Tariff")
|
||||
.HasColumnName("tariff")
|
||||
|
@ -69,7 +69,7 @@ namespace ASC.Core.Common.Migrations.Npgsql.CoreDbContextNpgsql
|
||||
schema: "onlyoffice",
|
||||
table: "tenants_quota",
|
||||
columns: new[] { "tenant", "active_users", "avangate_id", "description", "features", "max_file_size", "max_total_size", "name", "visible" },
|
||||
values: new object[] { -1, 10000, "0", null, "docs,domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption", 102400L, 10995116277760L, "default", false });
|
||||
values: new object[] { -1, 10000, "0", null, "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore", 102400L, 10995116277760L, "default", false });
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "tenants_quotarow",
|
||||
@ -96,7 +96,8 @@ namespace ASC.Core.Common.Migrations.Npgsql.CoreDbContextNpgsql
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
tenant = table.Column<int>(nullable: false),
|
||||
tariff = table.Column<int>(nullable: false),
|
||||
stamp = table.Column<DateTime>(nullable: false),
|
||||
stamp = table.Column<DateTime>(nullable: false),
|
||||
quantity = table.Column<int>(type: "int", nullable: false),
|
||||
comment = table.Column<string>(maxLength: 255, nullable: true, defaultValueSql: "NULL"),
|
||||
create_on = table.Column<DateTime>(nullable: false, defaultValueSql: "CURRENT_TIMESTAMP")
|
||||
},
|
||||
|
@ -671,7 +671,7 @@ namespace ASC.Core.Common.Migrations.Npgsql.CoreDbContextNpgsql
|
||||
Tenant = -1,
|
||||
ActiveUsers = 10000,
|
||||
AvangateId = "0",
|
||||
Features = "docs,domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption",
|
||||
Features = "domain,audit,controlpanel,healthcheck,ldap,sso,whitelabel,branding,ssbranding,update,support,portals:10000,discencryption,privacyroom,restore",
|
||||
MaxFileSize = 102400L,
|
||||
MaxTotalSize = 10995116277760L,
|
||||
Name = "default",
|
||||
@ -743,7 +743,11 @@ namespace ASC.Core.Common.Migrations.Npgsql.CoreDbContextNpgsql
|
||||
|
||||
b.Property<DateTime>("Stamp")
|
||||
.HasColumnName("stamp")
|
||||
.HasColumnType("timestamp without time zone");
|
||||
.HasColumnType("timestamp without time zone");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("quantity");
|
||||
|
||||
b.Property<int>("Tariff")
|
||||
.HasColumnName("tariff")
|
||||
|
@ -228,6 +228,31 @@ namespace ASC.Core.Common.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
Ouput = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".docx"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".odt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".pdf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".rtf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fodp",
|
||||
Ouput = ".odp"
|
||||
|
@ -170,7 +170,12 @@ namespace ASC.Core.Common.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
{ ".fodt", ".txt" },
|
||||
{ ".html", ".docx" },
|
||||
{ ".fods", ".xlsx" },
|
||||
{ ".xps", ".pdf" }
|
||||
{ ".xps", ".pdf" },
|
||||
{ ".fb2", ".docx" },
|
||||
{ ".fb2", ".odt" },
|
||||
{ ".fb2", ".pdf" },
|
||||
{ ".fb2", ".rtf" },
|
||||
{ ".fb2", ".txt" }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,31 @@ namespace ASC.Core.Common.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
Ouput = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".docx"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".odt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".pdf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".rtf"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fb2",
|
||||
Ouput = ".txt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Input = ".fodp",
|
||||
Ouput = ".odp"
|
||||
|
@ -33,9 +33,8 @@ using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Common.Utils;
|
||||
using ASC.Notify.Messages;
|
||||
using ASC.Notify.Patterns;
|
||||
using ASC.Notify.Patterns;
|
||||
|
||||
using MailKit;
|
||||
using MailKit.Security;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@ -287,10 +286,11 @@ namespace ASC.Core.Notify.Senders
|
||||
|
||||
var smtpClient = new MailKit.Net.Smtp.SmtpClient
|
||||
{
|
||||
ServerCertificateValidationCallback = (sender, certificate, chain, errors) =>
|
||||
sslCertificatePermit || MailService.DefaultServerCertificateValidationCallback(sender, certificate, chain, errors),
|
||||
Timeout = NETWORK_TIMEOUT
|
||||
};
|
||||
};
|
||||
|
||||
if (sslCertificatePermit)
|
||||
smtpClient.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
|
||||
|
||||
return smtpClient;
|
||||
}
|
||||
|
@ -191,7 +191,65 @@ namespace ASC.Core.Tenants
|
||||
{
|
||||
get { return GetFeature("privacyroom"); }
|
||||
set { SetFeature("privacyroom", value); }
|
||||
}
|
||||
}
|
||||
|
||||
public bool EnableMailServer
|
||||
{
|
||||
get { return GetFeature("mailserver"); }
|
||||
set { SetFeature("mailserver", value); }
|
||||
}
|
||||
|
||||
public int CountAdmin
|
||||
{
|
||||
get
|
||||
{
|
||||
var features = (Features ?? string.Empty).Split(' ', ',', ';').ToList();
|
||||
var admin = features.FirstOrDefault(f => f.StartsWith("admin:"));
|
||||
int countAdmin;
|
||||
if (admin == null || !int.TryParse(admin.Replace("admin:", ""), out countAdmin))
|
||||
{
|
||||
countAdmin = int.MaxValue;
|
||||
}
|
||||
return countAdmin;
|
||||
}
|
||||
set
|
||||
{
|
||||
var features = (Features ?? string.Empty).Split(' ', ',', ';').ToList();
|
||||
var admin = features.FirstOrDefault(f => f.StartsWith("admin:"));
|
||||
features.Remove(admin);
|
||||
if (value > 0)
|
||||
{
|
||||
features.Add("admin:" + value);
|
||||
}
|
||||
Features = string.Join(",", features.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public bool Restore
|
||||
{
|
||||
get { return GetFeature("restore"); }
|
||||
set { SetFeature("restore", value); }
|
||||
}
|
||||
|
||||
public bool AutoBackup
|
||||
{
|
||||
get { return GetFeature("autobackup"); }
|
||||
set { SetFeature("autobackup", value); }
|
||||
}
|
||||
|
||||
public bool Oauth
|
||||
{
|
||||
get { return GetFeature("oauth"); }
|
||||
set { SetFeature("oauth", value); }
|
||||
}
|
||||
|
||||
public bool ContentSearch
|
||||
{
|
||||
get { return GetFeature("contentsearch"); }
|
||||
set { SetFeature("contentsearch", value); }
|
||||
}
|
||||
|
||||
|
||||
public int CountPortals
|
||||
{
|
||||
get
|
||||
@ -215,8 +273,13 @@ namespace ASC.Core.Tenants
|
||||
}
|
||||
Features = string.Join(",", features.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool ThirdParty
|
||||
{
|
||||
get { return GetFeature("thirdparty"); }
|
||||
set { SetFeature("thirdparty", value); }
|
||||
}
|
||||
|
||||
public TenantQuota()
|
||||
{
|
||||
|
@ -1,143 +1,143 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
///*
|
||||
// *
|
||||
// * (c) Copyright Ascensio System Limited 2010-2018
|
||||
// *
|
||||
// * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
// * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
// * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
// *
|
||||
// * You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
// *
|
||||
// * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
// * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
// *
|
||||
// * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
// * relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
// * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
// * in every copy of the program you distribute.
|
||||
// * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
// *
|
||||
//*/
|
||||
|
||||
|
||||
#if DEBUG
|
||||
namespace ASC.Core.Common.Tests
|
||||
{
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
//#if DEBUG
|
||||
//namespace ASC.Core.Common.Tests
|
||||
//{
|
||||
// using System.Linq;
|
||||
// using System.Text.Json;
|
||||
|
||||
using ASC.Core.Billing;
|
||||
using ASC.Core.Data;
|
||||
using ASC.Core.Tenants;
|
||||
// using ASC.Core.Billing;
|
||||
// using ASC.Core.Data;
|
||||
// using ASC.Core.Tenants;
|
||||
|
||||
using NUnit.Framework;
|
||||
// using NUnit.Framework;
|
||||
|
||||
[TestFixture]
|
||||
class DbQuotaServiceTest : DbBaseTest<DbQuotaService>
|
||||
{
|
||||
public DbQuotaServiceTest()
|
||||
{
|
||||
}
|
||||
// [TestFixture]
|
||||
// class DbQuotaServiceTest : DbBaseTest<DbQuotaService>
|
||||
// {
|
||||
// public DbQuotaServiceTest()
|
||||
// {
|
||||
// }
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void ClearData()
|
||||
{
|
||||
Service.RemoveTenantQuota(Tenant);
|
||||
foreach (var row in Service.FindTenantQuotaRows(Tenant))
|
||||
{
|
||||
//DeleteQuotaRow(row);
|
||||
}
|
||||
}
|
||||
// [OneTimeSetUp]
|
||||
// public void ClearData()
|
||||
// {
|
||||
// Service.RemoveTenantQuota(Tenant);
|
||||
// foreach (var row in Service.FindTenantQuotaRows(Tenant))
|
||||
// {
|
||||
// //DeleteQuotaRow(row);
|
||||
// }
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void QuotaMethod()
|
||||
{
|
||||
var quota1 = new TenantQuota(Tenant)
|
||||
{
|
||||
MaxFileSize = 3,
|
||||
MaxTotalSize = 4,
|
||||
ActiveUsers = 30,
|
||||
};
|
||||
Service.SaveTenantQuota(quota1);
|
||||
CompareQuotas(quota1, Service.GetTenantQuota(quota1.Id));
|
||||
// [Test]
|
||||
// public void QuotaMethod()
|
||||
// {
|
||||
// var quota1 = new TenantQuota(Tenant)
|
||||
// {
|
||||
// MaxFileSize = 3,
|
||||
// MaxTotalSize = 4,
|
||||
// ActiveUsers = 30,
|
||||
// };
|
||||
// Service.SaveTenantQuota(quota1);
|
||||
// CompareQuotas(quota1, Service.GetTenantQuota(quota1.Id));
|
||||
|
||||
Service.RemoveTenantQuota(Tenant);
|
||||
Assert.IsNull(Service.GetTenantQuota(quota1.Id));
|
||||
// Service.RemoveTenantQuota(Tenant);
|
||||
// Assert.IsNull(Service.GetTenantQuota(quota1.Id));
|
||||
|
||||
var row = new TenantQuotaRow { Tenant = this.Tenant, Path = "path", Counter = 1000, Tag = "tag" };
|
||||
Service.SetTenantQuotaRow(row, false);
|
||||
// var row = new TenantQuotaRow { Tenant = this.Tenant, Path = "path", Counter = 1000, Tag = "tag" };
|
||||
// Service.SetTenantQuotaRow(row, false);
|
||||
|
||||
var rows = Service.FindTenantQuotaRows(Tenant).ToList();
|
||||
CompareQuotaRows(row, rows.Find(r => r.Tenant == row.Tenant && r.Tag == row.Tag));
|
||||
// var rows = Service.FindTenantQuotaRows(Tenant).ToList();
|
||||
// CompareQuotaRows(row, rows.Find(r => r.Tenant == row.Tenant && r.Tag == row.Tag));
|
||||
|
||||
Service.SetTenantQuotaRow(row, true);
|
||||
row.Counter += 1000;
|
||||
rows = Service.FindTenantQuotaRows(Tenant).ToList();
|
||||
CompareQuotaRows(row, rows.Find(r => r.Tenant == row.Tenant && r.Tag == row.Tag));
|
||||
// Service.SetTenantQuotaRow(row, true);
|
||||
// row.Counter += 1000;
|
||||
// rows = Service.FindTenantQuotaRows(Tenant).ToList();
|
||||
// CompareQuotaRows(row, rows.Find(r => r.Tenant == row.Tenant && r.Tag == row.Tag));
|
||||
|
||||
//DeleteQuotaRow(row);
|
||||
}
|
||||
// //DeleteQuotaRow(row);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void SerializeTest()
|
||||
{
|
||||
var quota1 = new TenantQuota(Tenant)
|
||||
{
|
||||
AvangateId = "1",
|
||||
Features = "trial,year",
|
||||
Name = "quota1",
|
||||
Price = 12.5m,
|
||||
Price2 = 45.23m,
|
||||
Visible = true,
|
||||
MaxFileSize = 3,
|
||||
MaxTotalSize = 4,
|
||||
ActiveUsers = 30,
|
||||
};
|
||||
// [Test]
|
||||
// public void SerializeTest()
|
||||
// {
|
||||
// var quota1 = new TenantQuota(Tenant)
|
||||
// {
|
||||
// AvangateId = "1",
|
||||
// Features = "trial,year",
|
||||
// Name = "quota1",
|
||||
// Price = 12.5m,
|
||||
// Price2 = 45.23m,
|
||||
// Visible = true,
|
||||
// MaxFileSize = 3,
|
||||
// MaxTotalSize = 4,
|
||||
// ActiveUsers = 30,
|
||||
// };
|
||||
|
||||
var json = JsonSerializer.Serialize(quota1);
|
||||
Assert.AreEqual("{\"Id\":1024,\"Name\":\"quota1\",\"MaxFileSize\":3,\"MaxTotalSize\":4,\"ActiveUsers\":30,\"Features\":\"trial,year\",\"Price\":12.5,\"Price2\":45.23,\"AvangateId\":\"1\",\"Visible\":true}", json);
|
||||
}
|
||||
// var json = JsonSerializer.Serialize(quota1);
|
||||
// Assert.AreEqual("{\"Id\":1024,\"Name\":\"quota1\",\"MaxFileSize\":3,\"MaxTotalSize\":4,\"ActiveUsers\":30,\"Features\":\"trial,year\",\"Price\":12.5,\"Price2\":45.23,\"AvangateId\":\"1\",\"Visible\":true}", json);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void SyncTest()
|
||||
{
|
||||
using var client = new TariffSyncClient();
|
||||
var quotas = client.GetTariffs(1, "key");
|
||||
Assert.AreNotEqual(0, quotas.Count());
|
||||
}
|
||||
// [Test]
|
||||
// public void SyncTest()
|
||||
// {
|
||||
// using var client = new TariffSyncClient();
|
||||
// var quotas = client.GetTariffs(1, "key");
|
||||
// Assert.AreNotEqual(0, quotas.Count());
|
||||
// }
|
||||
|
||||
private void CompareQuotas(TenantQuota q1, TenantQuota q2)
|
||||
{
|
||||
Assert.AreEqual(q1.Id, q2.Id);
|
||||
Assert.AreEqual(q1.Name, q2.Name);
|
||||
Assert.AreEqual(q1.MaxFileSize, q2.MaxFileSize);
|
||||
Assert.AreEqual(q1.MaxTotalSize, q2.MaxTotalSize);
|
||||
Assert.AreEqual(q1.ActiveUsers, q2.ActiveUsers);
|
||||
Assert.AreEqual(q1.Features, q2.Features);
|
||||
Assert.AreEqual(q1.Price, q2.Price);
|
||||
Assert.AreEqual(q1.Price2, q2.Price2);
|
||||
Assert.AreEqual(q1.AvangateId, q2.AvangateId);
|
||||
Assert.AreEqual(q1.Visible, q2.Visible);
|
||||
}
|
||||
// private void CompareQuotas(TenantQuota q1, TenantQuota q2)
|
||||
// {
|
||||
// Assert.AreEqual(q1.Id, q2.Id);
|
||||
// Assert.AreEqual(q1.Name, q2.Name);
|
||||
// Assert.AreEqual(q1.MaxFileSize, q2.MaxFileSize);
|
||||
// Assert.AreEqual(q1.MaxTotalSize, q2.MaxTotalSize);
|
||||
// Assert.AreEqual(q1.ActiveUsers, q2.ActiveUsers);
|
||||
// Assert.AreEqual(q1.Features, q2.Features);
|
||||
// Assert.AreEqual(q1.Price, q2.Price);
|
||||
// Assert.AreEqual(q1.Price2, q2.Price2);
|
||||
// Assert.AreEqual(q1.AvangateId, q2.AvangateId);
|
||||
// Assert.AreEqual(q1.Visible, q2.Visible);
|
||||
// }
|
||||
|
||||
private void CompareQuotaRows(TenantQuotaRow r1, TenantQuotaRow r2)
|
||||
{
|
||||
Assert.AreEqual(r1.Path, r2.Path);
|
||||
Assert.AreEqual(r1.Tag, r2.Tag);
|
||||
Assert.AreEqual(r1.Tenant, r2.Tenant);
|
||||
Assert.AreEqual(r1.Counter, r2.Counter);
|
||||
}
|
||||
// private void CompareQuotaRows(TenantQuotaRow r1, TenantQuotaRow r2)
|
||||
// {
|
||||
// Assert.AreEqual(r1.Path, r2.Path);
|
||||
// Assert.AreEqual(r1.Tag, r2.Tag);
|
||||
// Assert.AreEqual(r1.Tenant, r2.Tenant);
|
||||
// Assert.AreEqual(r1.Counter, r2.Counter);
|
||||
// }
|
||||
|
||||
//private void DeleteQuotaRow(TenantQuotaRow row)
|
||||
//{
|
||||
// var d = new SqlDelete(DbQuotaService.tenants_quotarow).Where("tenant", row.Tenant).Where("path", row.Path);
|
||||
// var dbManager = DbOptionsManager.Value;
|
||||
// dbManager.ExecuteNonQuery(d);
|
||||
//}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// //private void DeleteQuotaRow(TenantQuotaRow row)
|
||||
// //{
|
||||
// // var d = new SqlDelete(DbQuotaService.tenants_quotarow).Where("tenant", row.Tenant).Where("path", row.Path);
|
||||
// // var dbManager = DbOptionsManager.Value;
|
||||
// // dbManager.ExecuteNonQuery(d);
|
||||
// //}
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
|
@ -1,92 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
///*
|
||||
// *
|
||||
// * (c) Copyright Ascensio System Limited 2010-2018
|
||||
// *
|
||||
// * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
// * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
// * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
// *
|
||||
// * You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
// *
|
||||
// * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
// * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
// *
|
||||
// * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
// * relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
// * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
// * in every copy of the program you distribute.
|
||||
// * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
// *
|
||||
//*/
|
||||
|
||||
|
||||
#if DEBUG
|
||||
namespace ASC.Core.Common.Tests
|
||||
{
|
||||
using System;
|
||||
//#if DEBUG
|
||||
//namespace ASC.Core.Common.Tests
|
||||
//{
|
||||
// using System;
|
||||
|
||||
using ASC.Core.Billing;
|
||||
// using ASC.Core.Billing;
|
||||
|
||||
using NUnit.Framework;
|
||||
// using NUnit.Framework;
|
||||
|
||||
[TestFixture]
|
||||
public class TariffServiceTest
|
||||
{
|
||||
private readonly ITariffService tariffService;
|
||||
// [TestFixture]
|
||||
// public class TariffServiceTest
|
||||
// {
|
||||
// private readonly ITariffService tariffService;
|
||||
|
||||
|
||||
public TariffServiceTest()
|
||||
{
|
||||
tariffService = new TariffService();
|
||||
}
|
||||
// public TariffServiceTest()
|
||||
// {
|
||||
// tariffService = new TariffService();
|
||||
// }
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestShoppingUriBatch()
|
||||
{
|
||||
using var bc = new BillingClient(true, null, null);
|
||||
var result = bc.GetPaymentUrls("0", new[] { "12", "13", "14", "0", "-2" });
|
||||
Assert.AreEqual(5, result.Count);
|
||||
}
|
||||
// [Test]
|
||||
// public void TestShoppingUriBatch()
|
||||
// {
|
||||
// using var bc = new BillingClient(true, null, null);
|
||||
// var result = bc.GetPaymentUrls("0", new[] { "12", "13", "14", "0", "-2" });
|
||||
// Assert.AreEqual(5, result.Count);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void TestPaymentInfo()
|
||||
{
|
||||
var payments = tariffService.GetPayments(918, DateTime.MinValue, DateTime.MaxValue);
|
||||
Assert.IsNotNull(payments);
|
||||
}
|
||||
// [Test]
|
||||
// public void TestPaymentInfo()
|
||||
// {
|
||||
// var payments = tariffService.GetPayments(918, DateTime.MinValue, DateTime.MaxValue);
|
||||
// Assert.IsNotNull(payments);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void TestTariff()
|
||||
{
|
||||
var tariff = tariffService.GetTariff(918);
|
||||
Assert.IsNotNull(tariff);
|
||||
}
|
||||
// [Test]
|
||||
// public void TestTariff()
|
||||
// {
|
||||
// var tariff = tariffService.GetTariff(918);
|
||||
// Assert.IsNotNull(tariff);
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void TestSetTariff()
|
||||
{
|
||||
var duedate = DateTime.UtcNow.AddMonths(1);
|
||||
tariffService.SetTariff(0, new Tariff { QuotaId = -1, DueDate = DateTime.MaxValue });
|
||||
tariffService.SetTariff(0, new Tariff { QuotaId = -21, DueDate = duedate });
|
||||
tariffService.SetTariff(0, new Tariff { QuotaId = -21, DueDate = duedate });
|
||||
tariffService.SetTariff(0, new Tariff { QuotaId = -1, DueDate = DateTime.MaxValue });
|
||||
}
|
||||
// [Test]
|
||||
// public void TestSetTariff()
|
||||
// {
|
||||
// var duedate = DateTime.UtcNow.AddMonths(1);
|
||||
// tariffService.SetTariff(0, new Tariff { QuotaId = -1, DueDate = DateTime.MaxValue });
|
||||
// tariffService.SetTariff(0, new Tariff { QuotaId = -21, DueDate = duedate });
|
||||
// tariffService.SetTariff(0, new Tariff { QuotaId = -21, DueDate = duedate });
|
||||
// tariffService.SetTariff(0, new Tariff { QuotaId = -1, DueDate = DateTime.MaxValue });
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void TestInvoice()
|
||||
{
|
||||
var payments = tariffService.GetPayments(918, DateTime.MinValue, DateTime.MaxValue);
|
||||
foreach (var p in payments)
|
||||
{
|
||||
var invoice = tariffService.GetInvoice(p.CartId);
|
||||
Assert.IsNotNull(invoice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// [Test]
|
||||
// public void TestInvoice()
|
||||
// {
|
||||
// var payments = tariffService.GetPayments(918, DateTime.MinValue, DateTime.MaxValue);
|
||||
// foreach (var p in payments)
|
||||
// {
|
||||
// var invoice = tariffService.GetInvoice(p.CartId);
|
||||
// Assert.IsNotNull(invoice);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//#endif
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#if DEBUG
|
||||
namespace ASC.Core.Common.Tests
|
||||
{
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.Billing;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
[TestFixture]
|
||||
public class TariffSyncServiceTest
|
||||
{
|
||||
private readonly ITariffSyncService tariffSyncService;
|
||||
|
||||
public IServiceProvider ServiceProvider { get; set; }
|
||||
public IConfiguration Configuration { get; set; }
|
||||
public IOptionsMonitor<ILog> Options { get; set; }
|
||||
|
||||
public TariffSyncServiceTest()
|
||||
{
|
||||
tariffSyncService = new TariffSyncService(null, null, null, null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetTeriffsTest()
|
||||
{
|
||||
var tariff = tariffSyncService.GetTariffs(70, null).FirstOrDefault(t => t.Id == -38);
|
||||
Assert.AreEqual(1024 * 1024 * 1024, tariff.MaxFileSize);
|
||||
tariff = tariffSyncService.GetTariffs(74, null).FirstOrDefault(t => t.Id == -38);
|
||||
Assert.AreEqual(100 * 1024 * 1024, tariff.MaxFileSize);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SyncTest()
|
||||
{
|
||||
using var wcfClient = new TariffSyncClient();
|
||||
var tariffs = wcfClient.GetTariffs(74, null);
|
||||
Assert.IsTrue(tariffs.Any());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -60,6 +60,19 @@ namespace ASC.Core.Users
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public int CoefficientOfVisitors
|
||||
{
|
||||
get
|
||||
{
|
||||
int count;
|
||||
if (!int.TryParse(Configuration["core:coefficient-of-visitors"], out count))
|
||||
{
|
||||
count = 2;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
private IConfiguration Configuration { get; }
|
||||
|
@ -31,6 +31,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Common.Utils;
|
||||
using ASC.Core;
|
||||
@ -45,13 +46,21 @@ namespace ASC.Data.Storage
|
||||
public abstract class BaseStorage : IDataStore
|
||||
{
|
||||
protected ILog Log { get; set; }
|
||||
protected TempStream TempStream { get; }
|
||||
protected TenantManager TenantManager { get; }
|
||||
protected PathUtils PathUtils { get; }
|
||||
protected EmailValidationKeyProvider EmailValidationKeyProvider { get; }
|
||||
protected IHttpContextAccessor HttpContextAccessor { get; }
|
||||
protected IOptionsMonitor<ILog> Options { get; }
|
||||
|
||||
public BaseStorage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IOptionsMonitor<ILog> options)
|
||||
{
|
||||
TempStream = tempStream;
|
||||
TenantManager = tenantManager;
|
||||
PathUtils = pathUtils;
|
||||
EmailValidationKeyProvider = emailValidationKeyProvider;
|
||||
@ -60,11 +69,14 @@ namespace ASC.Data.Storage
|
||||
}
|
||||
|
||||
public BaseStorage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IOptionsMonitor<ILog> options) : this(tenantManager,
|
||||
IOptionsMonitor<ILog> options) : this(
|
||||
tempStream,
|
||||
tenantManager,
|
||||
pathUtils,
|
||||
emailValidationKeyProvider,
|
||||
options)
|
||||
@ -228,12 +240,6 @@ namespace ASC.Data.Storage
|
||||
|
||||
public virtual bool IsSupportChunking { get { return false; } }
|
||||
|
||||
protected TenantManager TenantManager { get; }
|
||||
protected PathUtils PathUtils { get; }
|
||||
protected EmailValidationKeyProvider EmailValidationKeyProvider { get; }
|
||||
protected IHttpContextAccessor HttpContextAccessor { get; }
|
||||
protected IOptionsMonitor<ILog> Options { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
public abstract void Delete(string domain, string path);
|
||||
|
@ -25,8 +25,9 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using System.IO;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.ChunkedUploader;
|
||||
|
||||
@ -40,20 +41,21 @@ namespace ASC.Data.Storage
|
||||
private readonly IDataStore source;
|
||||
private readonly IDataStore destination;
|
||||
private readonly long maxChunkUploadSize;
|
||||
private readonly int chunksize;
|
||||
private readonly int chunksize;
|
||||
private IOptionsMonitor<ILog> Option { get; }
|
||||
private TempStream TempStream { get; }
|
||||
|
||||
public CrossModuleTransferUtility(IOptionsMonitor<ILog> option, IDataStore source, IDataStore destination)
|
||||
public CrossModuleTransferUtility(IOptionsMonitor<ILog> option, TempStream tempStream, IDataStore source, IDataStore destination)
|
||||
{
|
||||
Log = option.Get("ASC.CrossModuleTransferUtility");
|
||||
Option = option;
|
||||
Option = option;
|
||||
TempStream = tempStream;
|
||||
this.source = source ?? throw new ArgumentNullException("source");
|
||||
this.destination = destination ?? throw new ArgumentNullException("destination");
|
||||
maxChunkUploadSize = 10 * 1024 * 1024;
|
||||
chunksize = 5 * 1024 * 1024;
|
||||
}
|
||||
|
||||
private IOptionsMonitor<ILog> Option { get; }
|
||||
|
||||
}
|
||||
|
||||
public void CopyFile(string srcDomain, string srcPath, string destDomain, string destPath)
|
||||
{
|
||||
if (srcDomain == null) throw new ArgumentNullException("srcDomain");
|
||||
|
@ -77,19 +77,21 @@ namespace ASC.Data.Storage.DiscStorage
|
||||
}
|
||||
|
||||
public DiscDataStore(
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IOptionsMonitor<ILog> options,
|
||||
EncryptionSettingsHelper encryptionSettingsHelper,
|
||||
EncryptionFactory encryptionFactory)
|
||||
: base(tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IOptionsMonitor<ILog> options,
|
||||
EncryptionSettingsHelper encryptionSettingsHelper,
|
||||
EncryptionFactory encryptionFactory)
|
||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
{
|
||||
EncryptionSettingsHelper = encryptionSettingsHelper;
|
||||
EncryptionFactory = encryptionFactory;
|
||||
}
|
||||
|
||||
public DiscDataStore(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
@ -97,7 +99,7 @@ namespace ASC.Data.Storage.DiscStorage
|
||||
IOptionsMonitor<ILog> options,
|
||||
EncryptionSettingsHelper encryptionSettingsHelper,
|
||||
EncryptionFactory encryptionFactory)
|
||||
: base(tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
{
|
||||
EncryptionSettingsHelper = encryptionSettingsHelper;
|
||||
EncryptionFactory = encryptionFactory;
|
||||
@ -171,7 +173,7 @@ namespace ASC.Data.Storage.DiscStorage
|
||||
public override Uri Save(string domain, string path, Stream stream)
|
||||
{
|
||||
Log.Debug("Save " + path);
|
||||
var buffered = stream.GetBuffered();
|
||||
var buffered = TempStream.GetBuffered(stream);
|
||||
if (QuotaController != null)
|
||||
{
|
||||
QuotaController.QuotaUsedCheck(buffered.Length);
|
||||
|
@ -28,15 +28,17 @@ using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
using ASC.Common;
|
||||
|
||||
namespace ASC.Data.Storage
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
private const int BufferSize = 2048;//NOTE: set to 2048 to fit in minimum tcp window
|
||||
|
||||
public static Stream IronReadStream(this IDataStore store, string domain, string path, int tryCount)
|
||||
public static Stream IronReadStream(this IDataStore store, TempStream tempStream, string domain, string path, int tryCount)
|
||||
{
|
||||
var ms = TempStream.Create();
|
||||
var ms = tempStream.Create();
|
||||
IronReadToStream(store, domain, path, tryCount, ms);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
return ms;
|
||||
|
@ -72,19 +72,21 @@ namespace ASC.Data.Storage.GoogleCloud
|
||||
private bool _lowerCasing = true;
|
||||
|
||||
public GoogleCloudStorage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IOptionsMonitor<ILog> options) : base(tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
IOptionsMonitor<ILog> options) : base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
{
|
||||
}
|
||||
|
||||
public GoogleCloudStorage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IOptionsMonitor<ILog> options) : base(tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
IOptionsMonitor<ILog> options) : base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
{
|
||||
}
|
||||
|
||||
@ -273,7 +275,7 @@ namespace ASC.Data.Storage.GoogleCloud
|
||||
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5)
|
||||
{
|
||||
|
||||
var buffered = stream.GetBuffered();
|
||||
var buffered = TempStream.GetBuffered(stream);
|
||||
|
||||
if (QuotaController != null)
|
||||
{
|
||||
@ -662,7 +664,7 @@ namespace ASC.Data.Storage.GoogleCloud
|
||||
using var storage = GetStorage();
|
||||
|
||||
var objectKey = MakePath(domain, path);
|
||||
var buffered = stream.GetBuffered();
|
||||
var buffered = TempStream.GetBuffered(stream);
|
||||
|
||||
var uploadObjectOptions = new UploadObjectOptions
|
||||
{
|
||||
|
@ -65,22 +65,24 @@ namespace ASC.Data.Storage.RackspaceCloud
|
||||
private readonly ILog _logger;
|
||||
|
||||
public RackspaceCloudStorage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IOptionsMonitor<ILog> options)
|
||||
: base(tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
{
|
||||
_logger = options.Get("ASC.Data.Storage.Rackspace.RackspaceCloudStorage");
|
||||
}
|
||||
|
||||
public RackspaceCloudStorage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IOptionsMonitor<ILog> options)
|
||||
: base(tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
{
|
||||
_logger = options.Get("ASC.Data.Storage.Rackspace.RackspaceCloudStorage");
|
||||
}
|
||||
@ -283,7 +285,7 @@ namespace ASC.Data.Storage.RackspaceCloud
|
||||
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5,
|
||||
DateTime? deleteAt = null, long? deleteAfter = null)
|
||||
{
|
||||
var buffered = stream.GetBuffered();
|
||||
var buffered = TempStream.GetBuffered(stream);
|
||||
|
||||
if (QuotaController != null)
|
||||
{
|
||||
|
@ -78,21 +78,23 @@ namespace ASC.Data.Storage.S3
|
||||
private string _subDir = string.Empty;
|
||||
|
||||
public S3Storage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IOptionsMonitor<ILog> options)
|
||||
: base(tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, options)
|
||||
{
|
||||
}
|
||||
|
||||
public S3Storage(
|
||||
TempStream tempStream,
|
||||
TenantManager tenantManager,
|
||||
PathUtils pathUtils,
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IOptionsMonitor<ILog> options)
|
||||
: base(tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
: base(tempStream, tenantManager, pathUtils, emailValidationKeyProvider, httpContextAccessor, options)
|
||||
{
|
||||
}
|
||||
|
||||
@ -218,7 +220,7 @@ namespace ASC.Data.Storage.S3
|
||||
public Uri Save(string domain, string path, Stream stream, string contentType,
|
||||
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5)
|
||||
{
|
||||
var buffered = stream.GetBuffered();
|
||||
var buffered = TempStream.GetBuffered(stream);
|
||||
if (QuotaController != null)
|
||||
{
|
||||
QuotaController.QuotaUsedCheck(buffered.Length);
|
||||
@ -618,7 +620,7 @@ namespace ASC.Data.Storage.S3
|
||||
using var client = GetClient();
|
||||
using var uploader = new TransferUtility(client);
|
||||
var objectKey = MakePath(domain, path);
|
||||
var buffered = stream.GetBuffered();
|
||||
var buffered = TempStream.GetBuffered(stream);
|
||||
var request = new TransferUtilityUploadRequest
|
||||
{
|
||||
BucketName = _bucket,
|
||||
|
@ -54,7 +54,8 @@ namespace ASC.Data.Storage
|
||||
private ICache Cache { get; set; }
|
||||
private static readonly object Locker;
|
||||
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
private TempStream TempStream { get; }
|
||||
private ICacheNotify<MigrationProgress> CacheMigrationNotify { get; }
|
||||
|
||||
static StorageUploader()
|
||||
@ -64,9 +65,10 @@ namespace ASC.Data.Storage
|
||||
Locker = new object();
|
||||
}
|
||||
|
||||
public StorageUploader(IServiceProvider serviceProvider, ICacheNotify<MigrationProgress> cacheMigrationNotify, ICache cache)
|
||||
public StorageUploader(IServiceProvider serviceProvider, TempStream tempStream, ICacheNotify<MigrationProgress> cacheMigrationNotify, ICache cache)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
ServiceProvider = serviceProvider;
|
||||
TempStream = tempStream;
|
||||
CacheMigrationNotify = cacheMigrationNotify;
|
||||
Cache = cache;
|
||||
}
|
||||
@ -82,7 +84,7 @@ namespace ASC.Data.Storage
|
||||
migrateOperation = Cache.Get<MigrateOperation>(GetCacheKey(tenantId));
|
||||
if (migrateOperation != null) return;
|
||||
|
||||
migrateOperation = new MigrateOperation(ServiceProvider, CacheMigrationNotify, tenantId, newStorageSettings, storageFactoryConfig);
|
||||
migrateOperation = new MigrateOperation(ServiceProvider, CacheMigrationNotify, tenantId, newStorageSettings, storageFactoryConfig, TempStream);
|
||||
Cache.Insert(GetCacheKey(tenantId), migrateOperation, DateTime.MaxValue);
|
||||
}
|
||||
|
||||
@ -133,20 +135,28 @@ namespace ASC.Data.Storage
|
||||
ConfigPath = "";
|
||||
}
|
||||
|
||||
public MigrateOperation(IServiceProvider serviceProvider, ICacheNotify<MigrationProgress> cacheMigrationNotify, int tenantId, StorageSettings settings, StorageFactoryConfig storageFactoryConfig)
|
||||
public MigrateOperation(
|
||||
IServiceProvider serviceProvider,
|
||||
ICacheNotify<MigrationProgress> cacheMigrationNotify,
|
||||
int tenantId,
|
||||
StorageSettings settings,
|
||||
StorageFactoryConfig storageFactoryConfig,
|
||||
TempStream tempStream)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
CacheMigrationNotify = cacheMigrationNotify;
|
||||
this.tenantId = tenantId;
|
||||
this.settings = settings;
|
||||
StorageFactoryConfig = storageFactoryConfig;
|
||||
StorageFactoryConfig = storageFactoryConfig;
|
||||
TempStream = tempStream;
|
||||
Modules = storageFactoryConfig.GetModuleList(ConfigPath, true);
|
||||
StepCount = Modules.Count();
|
||||
Log = serviceProvider.GetService<IOptionsMonitor<ILog>>().CurrentValue;
|
||||
}
|
||||
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
private StorageFactoryConfig StorageFactoryConfig { get; }
|
||||
private StorageFactoryConfig StorageFactoryConfig { get; }
|
||||
private TempStream TempStream { get; }
|
||||
private ICacheNotify<MigrationProgress> CacheMigrationNotify { get; }
|
||||
|
||||
protected override void DoJob()
|
||||
@ -168,7 +178,7 @@ namespace ASC.Data.Storage
|
||||
var store = storageFactory.GetStorageFromConsumer(ConfigPath, tenantId.ToString(), module, storageSettingsHelper.DataStoreConsumer(settings));
|
||||
var domains = StorageFactoryConfig.GetDomainList(ConfigPath, module).ToList();
|
||||
|
||||
var crossModuleTransferUtility = new CrossModuleTransferUtility(options, oldStore, store);
|
||||
var crossModuleTransferUtility = new CrossModuleTransferUtility(options, TempStream, oldStore, store);
|
||||
|
||||
string[] files;
|
||||
foreach (var domain in domains)
|
||||
|
@ -17,7 +17,9 @@ namespace ASC.Data.Backup.EF.Model
|
||||
[Column("is_scheduled")]
|
||||
public bool IsScheduled { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Hash { get; set; }
|
||||
|
||||
[Column("storage_type")]
|
||||
public BackupStorageType StorageType { get; set; }
|
||||
|
@ -53,18 +53,27 @@ namespace ASC.Data.Backup.Tasks
|
||||
public bool DeleteBackupFileAfterCompletion { get; set; }
|
||||
public bool BlockOldPortalAfterStart { get; set; }
|
||||
public bool DeleteOldPortalAfterCompletion { get; set; }
|
||||
private IOptionsMonitor<ILog> Options { get; set; }
|
||||
private IOptionsMonitor<ILog> Options { get; set; }
|
||||
private TempStream TempStream { get; }
|
||||
private IServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
public int Limit { get; private set; }
|
||||
|
||||
public TransferPortalTask(DbFactory dbFactory, IServiceProvider serviceProvider, IOptionsMonitor<ILog> options, StorageFactory storageFactory, StorageFactoryConfig storageFactoryConfig, ModuleProvider moduleProvider)
|
||||
public TransferPortalTask(
|
||||
DbFactory dbFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IOptionsMonitor<ILog> options,
|
||||
StorageFactory storageFactory,
|
||||
StorageFactoryConfig storageFactoryConfig,
|
||||
ModuleProvider moduleProvider,
|
||||
TempStream tempStream)
|
||||
: base(dbFactory, options, storageFactory, storageFactoryConfig, moduleProvider)
|
||||
{
|
||||
DeleteBackupFileAfterCompletion = true;
|
||||
BlockOldPortalAfterStart = true;
|
||||
DeleteOldPortalAfterCompletion = true;
|
||||
Options = options;
|
||||
Options = options;
|
||||
TempStream = tempStream;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
@ -163,7 +172,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
{
|
||||
var baseStorage = StorageFactory.GetStorage(ConfigPath, TenantId.ToString(), group.Key);
|
||||
var destStorage = StorageFactory.GetStorage(ToConfigPath, columnMapper.GetTenantMapping().ToString(), group.Key);
|
||||
var utility = new CrossModuleTransferUtility(Options, baseStorage, destStorage);
|
||||
var utility = new CrossModuleTransferUtility(Options, TempStream, baseStorage, destStorage);
|
||||
|
||||
foreach (var file in group)
|
||||
{
|
||||
|
@ -70,7 +70,8 @@ namespace ASC.Files.Core.Data
|
||||
private IDaoFactory DaoFactory { get; }
|
||||
private ChunkedUploadSessionHolder ChunkedUploadSessionHolder { get; }
|
||||
private ProviderFolderDao ProviderFolderDao { get; }
|
||||
private CrossDao CrossDao { get; }
|
||||
private CrossDao CrossDao { get; }
|
||||
public TempStream TempStream { get; }
|
||||
|
||||
public FileDao(
|
||||
FactoryIndexerFile factoryIndexer,
|
||||
@ -1424,10 +1425,14 @@ namespace ASC.Files.Core.Data
|
||||
using var stream = GetFileStream(file);
|
||||
if (stream == null) return dbFile;
|
||||
|
||||
dbFile.Document = new Document
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
Data = Convert.ToBase64String(stream.GetCorrectBuffer())
|
||||
};
|
||||
stream.CopyTo(ms);
|
||||
dbFile.Document = new Document
|
||||
{
|
||||
Data = Convert.ToBase64String(ms.GetBuffer())
|
||||
};
|
||||
}
|
||||
|
||||
return dbFile;
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ namespace ASC.Files.Core.EF
|
||||
public string Comment { get; set; }
|
||||
public string Changes { get; set; }
|
||||
public bool Encrypted { get; set; }
|
||||
public ForcesaveType Forcesave { get; set; }
|
||||
public ForcesaveType Forcesave { get; set; }
|
||||
public bool Thumb { get; set; }
|
||||
|
||||
|
||||
[Nested]
|
||||
@ -140,7 +141,9 @@ namespace ASC.Files.Core.EF
|
||||
.HasColumnName("create_on")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
entity.Property(e => e.CurrentVersion).HasColumnName("current_version");
|
||||
entity.Property(e => e.CurrentVersion).HasColumnName("current_version");
|
||||
|
||||
entity.Property(e => e.Thumb).HasColumnName("thumb");
|
||||
|
||||
entity.Property(e => e.Encrypted).HasColumnName("encrypted");
|
||||
|
||||
@ -228,7 +231,9 @@ namespace ASC.Files.Core.EF
|
||||
|
||||
entity.Property(e => e.CreateOn).HasColumnName("create_on");
|
||||
|
||||
entity.Property(e => e.CurrentVersion).HasColumnName("current_version");
|
||||
entity.Property(e => e.CurrentVersion).HasColumnName("current_version");
|
||||
|
||||
entity.Property(e => e.Thumb).HasColumnName("thumb");
|
||||
|
||||
entity.Property(e => e.Encrypted).HasColumnName("encrypted");
|
||||
|
||||
|
@ -52,13 +52,15 @@ namespace ASC.Files.Thirdparty.Sharpbox
|
||||
{
|
||||
[Scope]
|
||||
internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao<string>
|
||||
{
|
||||
{
|
||||
private TempStream TempStream { get; }
|
||||
private CrossDao CrossDao { get; }
|
||||
private SharpBoxDaoSelector SharpBoxDaoSelector { get; }
|
||||
private IFileDao<int> FileDao { get; }
|
||||
|
||||
public SharpBoxFileDao(
|
||||
IServiceProvider serviceProvider,
|
||||
IServiceProvider serviceProvider,
|
||||
TempStream tempStream,
|
||||
UserManager userManager,
|
||||
TenantManager tenantManager,
|
||||
TenantUtil tenantUtil,
|
||||
@ -70,7 +72,8 @@ namespace ASC.Files.Thirdparty.Sharpbox
|
||||
SharpBoxDaoSelector sharpBoxDaoSelector,
|
||||
IFileDao<int> fileDao)
|
||||
: base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility)
|
||||
{
|
||||
{
|
||||
TempStream = tempStream;
|
||||
CrossDao = crossDao;
|
||||
SharpBoxDaoSelector = sharpBoxDaoSelector;
|
||||
FileDao = fileDao;
|
||||
@ -303,7 +306,7 @@ namespace ASC.Files.Thirdparty.Sharpbox
|
||||
|
||||
try
|
||||
{
|
||||
entry.GetDataTransferAccessor().Transfer(fileStream.GetBuffered(), nTransferDirection.nUpload);
|
||||
entry.GetDataTransferAccessor().Transfer(TempStream.GetBuffered(fileStream), nTransferDirection.nUpload);
|
||||
}
|
||||
catch (SharpBoxException e)
|
||||
{
|
||||
|
@ -264,7 +264,11 @@ namespace ASC.Files.Core.Migrations.MySql.FilesDbContextMySql
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("version_group")
|
||||
.HasDefaultValueSql("'1'");
|
||||
.HasDefaultValueSql("'1'");
|
||||
|
||||
b.Property<bool>("Thumb")
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("thumb");
|
||||
|
||||
b.HasKey("TenantId", "Id", "Version")
|
||||
.HasName("PRIMARY");
|
||||
@ -460,7 +464,7 @@ namespace ASC.Files.Core.Migrations.MySql.FilesDbContextMySql
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("varchar(100)")
|
||||
.HasColumnType("varchar(512)")
|
||||
.HasColumnName("password")
|
||||
.UseCollation("utf8_general_ci")
|
||||
.HasCharSet("utf8");
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
@ -51,7 +52,8 @@ namespace ASC.Files.Core.Migrations.MySql.FilesDbContextMySql
|
||||
changes = table.Column<string>(type: "mediumtext", nullable: true, collation: "utf8_general_ci")
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
encrypted = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
forcesave = table.Column<int>(type: "int", nullable: false)
|
||||
forcesave = table.Column<int>(type: "int", nullable: false),
|
||||
thumb = table.Column<bool>(type: "tinyint(1)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -165,7 +167,7 @@ namespace ASC.Files.Core.Migrations.MySql.FilesDbContextMySql
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
user_name = table.Column<string>(type: "varchar(100)", nullable: false, collation: "utf8_general_ci")
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
password = table.Column<string>(type: "varchar(100)", nullable: false, collation: "utf8_general_ci")
|
||||
password = table.Column<string>(type: "varchar(512)", nullable: false, collation: "utf8_general_ci")
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
token = table.Column<string>(type: "text", nullable: true, collation: "utf8_general_ci")
|
||||
.Annotation("MySql:CharSet", "utf8"),
|
||||
|
@ -262,7 +262,11 @@ namespace ASC.Files.Core.Migrations.MySql.FilesDbContextMySql
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("version_group")
|
||||
.HasDefaultValueSql("'1'");
|
||||
.HasDefaultValueSql("'1'");
|
||||
|
||||
b.Property<bool>("Thumb")
|
||||
.HasColumnType("tinyint(1)")
|
||||
.HasColumnName("thumb");
|
||||
|
||||
b.HasKey("TenantId", "Id", "Version")
|
||||
.HasName("PRIMARY");
|
||||
@ -458,7 +462,7 @@ namespace ASC.Files.Core.Migrations.MySql.FilesDbContextMySql
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("varchar(100)")
|
||||
.HasColumnType("varchar(512)")
|
||||
.HasColumnName("password")
|
||||
.UseCollation("utf8_general_ci")
|
||||
.HasCharSet("utf8");
|
||||
|
@ -322,6 +322,10 @@ namespace ASC.Files.Core.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
.HasColumnName("version_group")
|
||||
.HasColumnType("integer")
|
||||
.HasDefaultValueSql("1");
|
||||
|
||||
b.Property<bool>("Thumb")
|
||||
.HasColumnName("thumb")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id", "TenantId", "Version")
|
||||
.HasName("files_file_pkey");
|
||||
@ -515,7 +519,7 @@ namespace ASC.Files.Core.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
.IsRequired()
|
||||
.HasColumnName("password")
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasMaxLength(100);
|
||||
.HasMaxLength(512);
|
||||
|
||||
b.Property<string>("Provider")
|
||||
.IsRequired()
|
||||
|
@ -66,7 +66,8 @@ namespace ASC.Files.Core.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
comment = table.Column<string>(maxLength: 255, nullable: true, defaultValueSql: "NULL::character varying"),
|
||||
changes = table.Column<string>(nullable: true),
|
||||
encrypted = table.Column<bool>(nullable: false),
|
||||
forcesave = table.Column<int>(nullable: false)
|
||||
forcesave = table.Column<int>(nullable: false),
|
||||
thumb = table.Column<bool>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@ -173,7 +174,7 @@ namespace ASC.Files.Core.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
provider = table.Column<string>(maxLength: 50, nullable: false, defaultValueSql: "'0'::character varying"),
|
||||
customer_title = table.Column<string>(maxLength: 400, nullable: false),
|
||||
user_name = table.Column<string>(maxLength: 100, nullable: false),
|
||||
password = table.Column<string>(maxLength: 100, nullable: false),
|
||||
password = table.Column<string>(maxLength: 512, nullable: false),
|
||||
token = table.Column<string>(nullable: true),
|
||||
user_id = table.Column<Guid>(maxLength: 38, nullable: false),
|
||||
folder_type = table.Column<int>(nullable: false),
|
||||
|
@ -150,7 +150,11 @@ namespace ASC.Files.Core.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("version_group")
|
||||
.HasColumnType("integer")
|
||||
.HasDefaultValueSql("1");
|
||||
.HasDefaultValueSql("1");
|
||||
|
||||
b.Property<bool>("Thumb")
|
||||
.HasColumnName("thumb")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.HasKey("Id", "TenantId", "Version")
|
||||
.HasName("files_file_pkey");
|
||||
@ -344,7 +348,7 @@ namespace ASC.Files.Core.Migrations.Npgsql.FilesDbContextNpgsql
|
||||
.IsRequired()
|
||||
.HasColumnName("password")
|
||||
.HasColumnType("character varying(100)")
|
||||
.HasMaxLength(100);
|
||||
.HasMaxLength(512);
|
||||
|
||||
b.Property<string>("Provider")
|
||||
.IsRequired()
|
||||
|
@ -35,7 +35,6 @@ using ASC.Common;
|
||||
using ASC.Common.Security.Authentication;
|
||||
using ASC.Common.Threading;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Data.Storage;
|
||||
using ASC.Files.Core;
|
||||
using ASC.Files.Core.Resources;
|
||||
using ASC.MessagingSystem;
|
||||
@ -69,16 +68,19 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
|
||||
|
||||
class FileDownloadOperation : ComposeFileOperation<FileDownloadOperationData<string>, FileDownloadOperationData<int>>
|
||||
{
|
||||
public FileDownloadOperation(IServiceProvider serviceProvider, FileOperation<FileDownloadOperationData<string>, string> f1, FileOperation<FileDownloadOperationData<int>, int> f2)
|
||||
public FileDownloadOperation(IServiceProvider serviceProvider, TempStream tempStream, FileOperation<FileDownloadOperationData<string>, string> f1, FileOperation<FileDownloadOperationData<int>, int> f2)
|
||||
: base(serviceProvider, f1, f2)
|
||||
{
|
||||
{
|
||||
TempStream = tempStream;
|
||||
}
|
||||
|
||||
public override FileOperationType OperationType
|
||||
{
|
||||
get { return FileOperationType.Download; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private TempStream TempStream { get; }
|
||||
|
||||
public override void RunJob(DistributedTask distributedTask, CancellationToken cancellationToken)
|
||||
{
|
||||
base.RunJob(distributedTask, cancellationToken);
|
||||
|
@ -42,13 +42,15 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
|
||||
[Singletone(Additional = typeof(FileOperationsManagerHelperExtention))]
|
||||
public class FileOperationsManager
|
||||
{
|
||||
private readonly DistributedTaskQueue tasks;
|
||||
|
||||
private readonly DistributedTaskQueue tasks;
|
||||
|
||||
private TempStream TempStream { get; }
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
|
||||
public FileOperationsManager(DistributedTaskCacheNotify distributedTaskCacheNotify, IServiceProvider serviceProvider)
|
||||
public FileOperationsManager(TempStream tempStream, DistributedTaskCacheNotify distributedTaskCacheNotify, IServiceProvider serviceProvider)
|
||||
{
|
||||
tasks = new DistributedTaskQueue(distributedTaskCacheNotify, "fileOperations", 10);
|
||||
tasks = new DistributedTaskQueue(distributedTaskCacheNotify, "fileOperations", 10);
|
||||
TempStream = tempStream;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
@ -127,7 +129,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
|
||||
|
||||
var op1 = new FileDownloadOperation<int>(ServiceProvider, new FileDownloadOperationData<int>(folders.Where(r => r.Key.ValueKind == JsonValueKind.Number).ToDictionary(r => r.Key.GetInt32(), r => r.Value), files.Where(r => r.Key.ValueKind == JsonValueKind.Number).ToDictionary(r => r.Key.GetInt32(), r => r.Value), tenant, headers));
|
||||
var op2 = new FileDownloadOperation<string>(ServiceProvider, new FileDownloadOperationData<string>(folders.Where(r => r.Key.ValueKind == JsonValueKind.String).ToDictionary(r => r.Key.GetString(), r => r.Value), files.Where(r => r.Key.ValueKind == JsonValueKind.String).ToDictionary(r => r.Key.GetString(), r => r.Value), tenant, headers));
|
||||
var op = new FileDownloadOperation(ServiceProvider, op2, op1);
|
||||
var op = new FileDownloadOperation(ServiceProvider, TempStream, op2, op1);
|
||||
|
||||
return QueueTask(userId, op);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user