Merge branch 'develop' into feature/get-thumbnail-from-thirdparty

This commit is contained in:
Anton Suhorukov 2022-06-17 13:18:03 +03:00
commit 29d3bb3fee
51 changed files with 2506 additions and 1904 deletions

View File

@ -126,13 +126,23 @@ public class EmployeeFullDtoHelper : EmployeeDtoHelper
//i => new UserInfo { ID = i.id }
var parameter = Expression.Parameter(typeof(User), "i");
var bindExprs = new List<MemberAssignment>();
if (apiContext.Check("Id"))
{
bindExprs.Add(Expression.Bind(typeof(UserInfo).GetProperty("ID"),
Expression.Property(parameter, typeof(User).GetProperty("Id"))));
}
var bindExprs = new List<MemberAssignment>();
//foreach (var field in apiContext.Fields)
//{
// var userInfoProp = typeof(UserInfo).GetProperty(field);
// var userProp = typeof(User).GetProperty(field);
// if (userInfoProp != null && userProp != null)
// {
// bindExprs.Add(Expression.Bind(userInfoProp, Expression.Property(parameter, userProp)));
// }
//}
if (apiContext.Check("Id"))
{
bindExprs.Add(Expression.Bind(typeof(UserInfo).GetProperty("Id"),
Expression.Property(parameter, typeof(User).GetProperty("Id"))));
}
var body = Expression.MemberInit(newExpr, bindExprs);
var lambda = Expression.Lambda<Func<User, UserInfo>>(body, parameter);

View File

@ -0,0 +1,42 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Common.Data;
public static class TypeExtension
{
public static string GetFormattedName(this Type type)
{
if (type.IsGenericType)
{
var genericArguments = type.GetGenericArguments()
.Select(x => x.Name)
.Aggregate((x1, x2) => $"{x1}, {x2}");
return $"{type.Name.Substring(0, type.Name.IndexOf("`"))}"
+ $"<{genericArguments}>";
}
return type.Name;
}
}

View File

@ -27,7 +27,7 @@
namespace ASC.Common.Log;
internal static partial class DistributedTaskQueueLogger
{
[LoggerMessage(Level = LogLevel.Trace, Message = "EnqueueTask '{distributedTaskId}' by instanse id '{instanceId}'")]
[LoggerMessage(Level = LogLevel.Trace, Message = "EnqueueTask '{DistributedTaskId}' by instanse id '{instanceId}'")]
public static partial void TraceEnqueueTask(this ILogger<DistributedTaskQueue> logger, string DistributedTaskId, int instanceId);
[LoggerMessage(Level = LogLevel.Trace, Message = "Publication DistributedTask '{DistributedTaskId}' by instanse id '{instanceId}' ")]

View File

@ -305,6 +305,13 @@ public class DistributedTaskQueue
private void SaveToCache(IEnumerable<DistributedTask> queueTasks)
{
if (!queueTasks.Any())
{
_distributedCache.Remove(_name);
return;
}
using var ms = new MemoryStream();
Serializer.Serialize(ms, queueTasks);
@ -332,21 +339,11 @@ public class DistributedTaskQueue
private IEnumerable<DistributedTask> DeleteOrphanCacheItem(IEnumerable<DistributedTask> queueTasks)
{
if (!queueTasks.Any())
{
return queueTasks;
}
var listTasks = queueTasks.ToList();
var orphans = queueTasks.Where(IsOrphanCacheItem);
listTasks.RemoveAll(IsOrphanCacheItem);
if (!orphans.Any())
{
return queueTasks;
}
queueTasks = queueTasks.Except(queueTasks);
SaveToCache(queueTasks);
SaveToCache(listTasks);
return queueTasks;
}

View File

@ -495,31 +495,36 @@ public class TariffService : ITariffService
var currentTariff = GetBillingInfo(tenant);
if (!tariffInfo.EqualsByParams(currentTariff))
{
using var tx = CoreDbContext.Database.BeginTransaction();
var strategy = CoreDbContext.Database.CreateExecutionStrategy();
// last record is not the same
var any = CoreDbContext.Tariffs
.Any(r => r.Tenant == tenant && r.Tariff == tariffInfo.QuotaId && r.Stamp == tariffInfo.DueDate && r.Quantity == tariffInfo.Quantity);
if (tariffInfo.DueDate == DateTime.MaxValue || renewal || any)
{
var efTariff = new DbTariff
strategy.Execute(() =>
{
Tenant = tenant,
Tariff = tariffInfo.QuotaId,
Stamp = tariffInfo.DueDate,
Quantity = tariffInfo.Quantity,
CreateOn = DateTime.UtcNow
};
using var tx = CoreDbContext.Database.BeginTransaction();
CoreDbContext.Tariffs.Add(efTariff);
CoreDbContext.SaveChanges();
// last record is not the same
var any = CoreDbContext.Tariffs
.Any(r => r.Tenant == tenant && r.Tariff == tariffInfo.QuotaId && r.Stamp == tariffInfo.DueDate && r.Quantity == tariffInfo.Quantity);
Cache.Remove(GetTariffCacheKey(tenant));
inserted = true;
}
if (tariffInfo.DueDate == DateTime.MaxValue || renewal || any)
{
var efTariff = new DbTariff
{
Tenant = tenant,
Tariff = tariffInfo.QuotaId,
Stamp = tariffInfo.DueDate,
Quantity = tariffInfo.Quantity,
CreateOn = DateTime.UtcNow
};
tx.Commit();
CoreDbContext.Tariffs.Add(efTariff);
CoreDbContext.SaveChanges();
Cache.Remove(GetTariffCacheKey(tenant));
inserted = true;
}
tx.Commit();
});
}
if (inserted)

View File

@ -76,17 +76,25 @@ class DbAzService : IAzService
public AzRecord SaveAce(int tenant, AzRecord r)
{
r.Tenant = tenant;
using var tx = UserDbContext.Database.BeginTransaction();
if (!ExistEscapeRecord(r))
var strategy = UserDbContext.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
InsertRecord(r);
}
else
{
// unescape
DeleteRecord(r);
}
tx.Commit();
using var tx = UserDbContext.Database.BeginTransaction();
if (!ExistEscapeRecord(r))
{
InsertRecord(r);
}
else
{
// unescape
DeleteRecord(r);
}
tx.Commit();
});
return r;
}
@ -94,18 +102,26 @@ class DbAzService : IAzService
public void RemoveAce(int tenant, AzRecord r)
{
r.Tenant = tenant;
using var tx = UserDbContext.Database.BeginTransaction();
if (ExistEscapeRecord(r))
{
// escape
InsertRecord(r);
}
else
{
DeleteRecord(r);
}
tx.Commit();
var strategy = UserDbContext.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
using var tx = UserDbContext.Database.BeginTransaction();
if (ExistEscapeRecord(r))
{
// escape
InsertRecord(r);
}
else
{
DeleteRecord(r);
}
tx.Commit();
});
}

View File

@ -90,18 +90,23 @@ class DbQuotaService : IQuotaService
public void RemoveTenantQuota(int id)
{
using var tr = CoreDbContext.Database.BeginTransaction();
var d = CoreDbContext.Quotas
.Where(r => r.Tenant == id)
.SingleOrDefault();
var strategy = CoreDbContext.Database.CreateExecutionStrategy();
if (d != null)
strategy.Execute(() =>
{
CoreDbContext.Quotas.Remove(d);
CoreDbContext.SaveChanges();
}
using var tr = CoreDbContext.Database.BeginTransaction();
var d = CoreDbContext.Quotas
.Where(r => r.Tenant == id)
.SingleOrDefault();
tr.Commit();
if (d != null)
{
CoreDbContext.Quotas.Remove(d);
CoreDbContext.SaveChanges();
}
tr.Commit();
});
}
@ -109,22 +114,27 @@ class DbQuotaService : IQuotaService
{
ArgumentNullException.ThrowIfNull(row);
using var tx = CoreDbContext.Database.BeginTransaction();
var strategy = CoreDbContext.Database.CreateExecutionStrategy();
var counter = CoreDbContext.QuotaRows
.Where(r => r.Path == row.Path && r.Tenant == row.Tenant)
.Select(r => r.Counter)
.Take(1)
.FirstOrDefault();
strategy.Execute(() =>
{
using var tx = CoreDbContext.Database.BeginTransaction();
var dbQuotaRow = _mapper.Map<TenantQuotaRow, DbQuotaRow>(row);
dbQuotaRow.Counter = exchange ? counter + row.Counter : row.Counter;
dbQuotaRow.LastModified = DateTime.UtcNow;
var counter = CoreDbContext.QuotaRows
.Where(r => r.Path == row.Path && r.Tenant == row.Tenant)
.Select(r => r.Counter)
.Take(1)
.FirstOrDefault();
CoreDbContext.AddOrUpdate(r => r.QuotaRows, dbQuotaRow);
CoreDbContext.SaveChanges();
var dbQuotaRow = _mapper.Map<TenantQuotaRow, DbQuotaRow>(row);
dbQuotaRow.Counter = exchange ? counter + row.Counter : row.Counter;
dbQuotaRow.LastModified = DateTime.UtcNow;
tx.Commit();
CoreDbContext.AddOrUpdate(r => r.QuotaRows, dbQuotaRow);
CoreDbContext.SaveChanges();
tx.Commit();
});
}
public IEnumerable<TenantQuotaRow> FindTenantQuotaRows(int tenantId)

View File

@ -185,21 +185,30 @@ public class DbSettingsManager
if (data.SequenceEqual(defaultData))
{
using var tr = WebstudioDbContext.Database.BeginTransaction();
// remove default settings
var s = WebstudioDbContext.WebstudioSettings
.Where(r => r.Id == settings.ID)
.Where(r => r.TenantId == tenantId)
.Where(r => r.UserId == userId)
.FirstOrDefault();
var strategy = WebstudioDbContext.Database.CreateExecutionStrategy();
if (s != null)
strategy.Execute(() =>
{
WebstudioDbContext.WebstudioSettings.Remove(s);
}
using var tr = WebstudioDbContext.Database.BeginTransaction();
// remove default settings
var s = WebstudioDbContext.WebstudioSettings
.Where(r => r.Id == settings.ID)
.Where(r => r.TenantId == tenantId)
.Where(r => r.UserId == userId)
.FirstOrDefault();
if (s != null)
{
WebstudioDbContext.WebstudioSettings.Remove(s);
}
WebstudioDbContext.SaveChanges();
tr.Commit();
});
WebstudioDbContext.SaveChanges();
tr.Commit();
}
else
{

View File

@ -162,25 +162,30 @@ public class DbSubscriptionService : ISubscriptionService
ArgumentNullException.ThrowIfNull(sourceId);
ArgumentNullException.ThrowIfNull(actionId);
using var tr = UserDbContext.Database.BeginTransaction();
var q = UserDbContext.Subscriptions
.Where(r => r.Tenant == tenant)
.Where(r => r.Source == sourceId)
.Where(r => r.Action == actionId);
if (objectId.Length != 0)
var strategy = UserDbContext.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
q = q.Where(r => r.Object == (objectId ?? string.Empty));
}
using var tr = UserDbContext.Database.BeginTransaction();
var q = UserDbContext.Subscriptions
.Where(r => r.Tenant == tenant)
.Where(r => r.Source == sourceId)
.Where(r => r.Action == actionId);
var sub = q.FirstOrDefault();
if (objectId.Length != 0)
{
q = q.Where(r => r.Object == (objectId ?? string.Empty));
}
if (sub != null)
{
UserDbContext.Subscriptions.Remove(sub);
}
var sub = q.FirstOrDefault();
tr.Commit();
if (sub != null)
{
UserDbContext.Subscriptions.Remove(sub);
}
tr.Commit();
});
}
@ -232,38 +237,47 @@ public class DbSubscriptionService : ISubscriptionService
{
ArgumentNullException.ThrowIfNull(m);
using var tr = UserDbContext.Database.BeginTransaction();
var strategy = UserDbContext.Database.CreateExecutionStrategy();
if (m.Methods == null || m.Methods.Length == 0)
strategy.Execute(() =>
{
var q = UserDbContext.SubscriptionMethods
.Where(r => r.Tenant == m.Tenant)
.Where(r => r.Source == m.Source)
.Where(r => r.Recipient == m.Recipient)
.Where(r => r.Action == m.Action);
using var tr = UserDbContext.Database.BeginTransaction();
var sm = q.FirstOrDefault();
if (sm != null)
if (m.Methods == null || m.Methods.Length == 0)
{
UserDbContext.SubscriptionMethods.Remove(sm);
var q = UserDbContext.SubscriptionMethods
.Where(r => r.Tenant == m.Tenant)
.Where(r => r.Source == m.Source)
.Where(r => r.Recipient == m.Recipient)
.Where(r => r.Action == m.Action);
var sm = q.FirstOrDefault();
if (sm != null)
{
UserDbContext.SubscriptionMethods.Remove(sm);
}
}
}
else
{
var sm = new DbSubscriptionMethod
else
{
Action = m.Action,
Recipient = m.Recipient,
Source = m.Source,
Tenant = m.Tenant,
Sender = string.Join("|", m.Methods)
};
UserDbContext.AddOrUpdate(r => r.SubscriptionMethods, sm);
}
var sm = new DbSubscriptionMethod
{
Action = m.Action,
Recipient = m.Recipient,
Source = m.Source,
Tenant = m.Tenant,
Sender = string.Join("|", m.Methods)
};
UserDbContext.AddOrUpdate(r => r.SubscriptionMethods, sm);
}
UserDbContext.SaveChanges();
tr.Commit();
});
UserDbContext.SaveChanges();
tr.Commit();
}

View File

@ -84,7 +84,8 @@ public class DbTenantService : ITenantService
public void ValidateDomain(string domain)
{
using var tr = TenantDbContext.Database.BeginTransaction();
// TODO: Why does open transaction?
// using var tr = TenantDbContext.Database.BeginTransaction();
ValidateDomain(domain, Tenant.DefaultTenant, true);
}
@ -228,93 +229,98 @@ public class DbTenantService : ITenantService
{
ArgumentNullException.ThrowIfNull(tenant);
using var tx = TenantDbContext.Database.BeginTransaction();
var strategy = TenantDbContext.Database.CreateExecutionStrategy();
if (!string.IsNullOrEmpty(tenant.MappedDomain))
strategy.Execute(() =>
{
var baseUrl = coreSettings.GetBaseDomain(tenant.HostedRegion);
using var tx = TenantDbContext.Database.BeginTransaction();
if (baseUrl != null && tenant.MappedDomain.EndsWith("." + baseUrl, StringComparison.InvariantCultureIgnoreCase))
if (!string.IsNullOrEmpty(tenant.MappedDomain))
{
ValidateDomain(tenant.MappedDomain.Substring(0, tenant.MappedDomain.Length - baseUrl.Length - 1), tenant.Id, false);
var baseUrl = coreSettings.GetBaseDomain(tenant.HostedRegion);
if (baseUrl != null && tenant.MappedDomain.EndsWith("." + baseUrl, StringComparison.InvariantCultureIgnoreCase))
{
ValidateDomain(tenant.MappedDomain.Substring(0, tenant.MappedDomain.Length - baseUrl.Length - 1), tenant.Id, false);
}
else
{
ValidateDomain(tenant.MappedDomain, tenant.Id, false);
}
}
if (tenant.Id == Tenant.DefaultTenant)
{
tenant.Version = TenantDbContext.TenantVersion
.Where(r => r.DefaultVersion == 1 || r.Id == 0)
.OrderByDescending(r => r.Id)
.Select(r => r.Id)
.FirstOrDefault();
tenant.LastModified = DateTime.UtcNow;
var dbTenant = _mapper.Map<Tenant, DbTenant>(tenant);
dbTenant = TenantDbContext.Tenants.Add(dbTenant).Entity;
TenantDbContext.SaveChanges();
tenant.Id = dbTenant.Id;
}
else
{
ValidateDomain(tenant.MappedDomain, tenant.Id, false);
}
}
var dbTenant = TenantDbContext.Tenants
.Where(r => r.Id == tenant.Id)
.FirstOrDefault();
if (tenant.Id == Tenant.DefaultTenant)
{
tenant.Version = TenantDbContext.TenantVersion
.Where(r => r.DefaultVersion == 1 || r.Id == 0)
.OrderByDescending(r => r.Id)
.Select(r => r.Id)
.FirstOrDefault();
if (dbTenant != null)
{
dbTenant.Alias = tenant.Alias.ToLowerInvariant();
dbTenant.MappedDomain = !string.IsNullOrEmpty(tenant.MappedDomain) ? tenant.MappedDomain.ToLowerInvariant() : null;
dbTenant.Version = tenant.Version;
dbTenant.VersionChanged = tenant.VersionChanged;
dbTenant.Name = tenant.Name ?? tenant.Alias;
dbTenant.Language = tenant.Language;
dbTenant.TimeZone = tenant.TimeZone;
dbTenant.TrustedDomainsRaw = tenant.GetTrustedDomains();
dbTenant.TrustedDomainsEnabled = tenant.TrustedDomainsType;
dbTenant.CreationDateTime = tenant.CreationDateTime;
dbTenant.Status = tenant.Status;
dbTenant.StatusChanged = tenant.StatusChangeDate;
dbTenant.PaymentId = tenant.PaymentId;
dbTenant.LastModified = tenant.LastModified = DateTime.UtcNow;
dbTenant.Industry = tenant.Industry;
dbTenant.Spam = tenant.Spam;
dbTenant.Calls = tenant.Calls;
}
tenant.LastModified = DateTime.UtcNow;
var dbTenant = _mapper.Map<Tenant, DbTenant>(tenant);
dbTenant = TenantDbContext.Tenants.Add(dbTenant).Entity;
TenantDbContext.SaveChanges();
tenant.Id = dbTenant.Id;
}
else
{
var dbTenant = TenantDbContext.Tenants
.Where(r => r.Id == tenant.Id)
.FirstOrDefault();
if (dbTenant != null)
{
dbTenant.Alias = tenant.Alias.ToLowerInvariant();
dbTenant.MappedDomain = !string.IsNullOrEmpty(tenant.MappedDomain) ? tenant.MappedDomain.ToLowerInvariant() : null;
dbTenant.Version = tenant.Version;
dbTenant.VersionChanged = tenant.VersionChanged;
dbTenant.Name = tenant.Name ?? tenant.Alias;
dbTenant.Language = tenant.Language;
dbTenant.TimeZone = tenant.TimeZone;
dbTenant.TrustedDomainsRaw = tenant.GetTrustedDomains();
dbTenant.TrustedDomainsEnabled = tenant.TrustedDomainsType;
dbTenant.CreationDateTime = tenant.CreationDateTime;
dbTenant.Status = tenant.Status;
dbTenant.StatusChanged = tenant.StatusChangeDate;
dbTenant.PaymentId = tenant.PaymentId;
dbTenant.LastModified = tenant.LastModified = DateTime.UtcNow;
dbTenant.Industry = tenant.Industry;
dbTenant.Spam = tenant.Spam;
dbTenant.Calls = tenant.Calls;
TenantDbContext.SaveChanges();
}
TenantDbContext.SaveChanges();
}
if (string.IsNullOrEmpty(tenant.PartnerId) && string.IsNullOrEmpty(tenant.AffiliateId) && string.IsNullOrEmpty(tenant.Campaign))
{
var p = TenantDbContext.TenantPartner
.Where(r => r.TenantId == tenant.Id)
.FirstOrDefault();
if (p != null)
if (string.IsNullOrEmpty(tenant.PartnerId) && string.IsNullOrEmpty(tenant.AffiliateId) && string.IsNullOrEmpty(tenant.Campaign))
{
TenantDbContext.TenantPartner.Remove(p);
var p = TenantDbContext.TenantPartner
.Where(r => r.TenantId == tenant.Id)
.FirstOrDefault();
if (p != null)
{
TenantDbContext.TenantPartner.Remove(p);
}
}
}
else
{
var tenantPartner = new DbTenantPartner
else
{
TenantId = tenant.Id,
PartnerId = tenant.PartnerId,
AffiliateId = tenant.AffiliateId,
Campaign = tenant.Campaign
};
var tenantPartner = new DbTenantPartner
{
TenantId = tenant.Id,
PartnerId = tenant.PartnerId,
AffiliateId = tenant.AffiliateId,
Campaign = tenant.Campaign
};
TenantDbContext.TenantPartner.Add(tenantPartner);
}
TenantDbContext.TenantPartner.Add(tenantPartner);
}
tx.Commit();
tx.Commit();
});
//CalculateTenantDomain(t);
return tenant;
@ -324,30 +330,35 @@ public class DbTenantService : ITenantService
{
var postfix = auto ? "_auto_deleted" : "_deleted";
using var tx = TenantDbContext.Database.BeginTransaction();
var strategy = TenantDbContext.Database.CreateExecutionStrategy();
var alias = TenantDbContext.Tenants
.Where(r => r.Id == id)
.Select(r => r.Alias)
.FirstOrDefault();
var count = TenantDbContext.Tenants
.Where(r => r.Alias.StartsWith(alias + postfix))
.Count();
var tenant = TenantDbContext.Tenants.Where(r => r.Id == id).FirstOrDefault();
if (tenant != null)
strategy.Execute(() =>
{
tenant.Alias = alias + postfix + (count > 0 ? count.ToString() : "");
tenant.Status = TenantStatus.RemovePending;
tenant.StatusChanged = DateTime.UtcNow;
tenant.LastModified = DateTime.UtcNow;
}
using var tx = TenantDbContext.Database.BeginTransaction();
TenantDbContext.SaveChanges();
var alias = TenantDbContext.Tenants
.Where(r => r.Id == id)
.Select(r => r.Alias)
.FirstOrDefault();
tx.Commit();
var count = TenantDbContext.Tenants
.Where(r => r.Alias.StartsWith(alias + postfix))
.Count();
var tenant = TenantDbContext.Tenants.Where(r => r.Id == id).FirstOrDefault();
if (tenant != null)
{
tenant.Alias = alias + postfix + (count > 0 ? count.ToString() : "");
tenant.Status = TenantStatus.RemovePending;
tenant.StatusChanged = DateTime.UtcNow;
tenant.LastModified = DateTime.UtcNow;
}
TenantDbContext.SaveChanges();
tx.Commit();
});
}
public IEnumerable<TenantVersion> GetTenantVersions()
@ -370,35 +381,40 @@ public class DbTenantService : ITenantService
public void SetTenantSettings(int tenant, string key, byte[] data)
{
using var tx = TenantDbContext.Database.BeginTransaction();
var strategy = TenantDbContext.Database.CreateExecutionStrategy();
if (data == null || data.Length == 0)
strategy.Execute(() =>
{
var settings = TenantDbContext.CoreSettings
.Where(r => r.Tenant == tenant)
.Where(r => r.Id == key)
.FirstOrDefault();
using var tx = TenantDbContext.Database.BeginTransaction();
if (settings != null)
if (data == null || data.Length == 0)
{
TenantDbContext.CoreSettings.Remove(settings);
var settings = TenantDbContext.CoreSettings
.Where(r => r.Tenant == tenant)
.Where(r => r.Id == key)
.FirstOrDefault();
if (settings != null)
{
TenantDbContext.CoreSettings.Remove(settings);
}
}
}
else
{
var settings = new DbCoreSettings
else
{
Id = key,
Tenant = tenant,
Value = data,
LastModified = DateTime.UtcNow
};
var settings = new DbCoreSettings
{
Id = key,
Tenant = tenant,
Value = data,
LastModified = DateTime.UtcNow
};
TenantDbContext.AddOrUpdate(r => r.CoreSettings, settings);
}
TenantDbContext.AddOrUpdate(r => r.CoreSettings, settings);
}
TenantDbContext.SaveChanges();
tx.Commit();
TenantDbContext.SaveChanges();
tx.Commit();
});
}
private IQueryable<DbTenant> TenantsQuery()

View File

@ -318,36 +318,41 @@ public class EFUserService : IUserService
var ids = CollectGroupChilds(tenant, id);
var stringIds = ids.Select(r => r.ToString()).ToList();
using var tr = UserDbContext.Database.BeginTransaction();
var strategy = UserDbContext.Database.CreateExecutionStrategy();
UserDbContext.Acl.RemoveRange(UserDbContext.Acl.Where(r => r.Tenant == tenant && ids.Any(i => i == r.Subject)));
UserDbContext.Subscriptions.RemoveRange(UserDbContext.Subscriptions.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)));
UserDbContext.SubscriptionMethods.RemoveRange(UserDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)));
var userGroups = UserDbContext.UserGroups.Where(r => r.Tenant == tenant && ids.Any(i => i == r.GroupId));
var groups = UserDbContext.Groups.Where(r => r.Tenant == tenant && ids.Any(i => i == r.Id));
if (immediate)
strategy.Execute(() =>
{
UserDbContext.UserGroups.RemoveRange(userGroups);
UserDbContext.Groups.RemoveRange(groups);
}
else
{
foreach (var ug in userGroups)
{
ug.Removed = true;
ug.LastModified = DateTime.UtcNow;
}
foreach (var g in groups)
{
g.Removed = true;
g.LastModified = DateTime.UtcNow;
}
}
using var tr = UserDbContext.Database.BeginTransaction();
UserDbContext.SaveChanges();
tr.Commit();
UserDbContext.Acl.RemoveRange(UserDbContext.Acl.Where(r => r.Tenant == tenant && ids.Any(i => i == r.Subject)));
UserDbContext.Subscriptions.RemoveRange(UserDbContext.Subscriptions.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)));
UserDbContext.SubscriptionMethods.RemoveRange(UserDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && stringIds.Any(i => i == r.Recipient)));
var userGroups = UserDbContext.UserGroups.Where(r => r.Tenant == tenant && ids.Any(i => i == r.GroupId));
var groups = UserDbContext.Groups.Where(r => r.Tenant == tenant && ids.Any(i => i == r.Id));
if (immediate)
{
UserDbContext.UserGroups.RemoveRange(userGroups);
UserDbContext.Groups.RemoveRange(groups);
}
else
{
foreach (var ug in userGroups)
{
ug.Removed = true;
ug.LastModified = DateTime.UtcNow;
}
foreach (var g in groups)
{
g.Removed = true;
g.LastModified = DateTime.UtcNow;
}
}
UserDbContext.SaveChanges();
tr.Commit();
});
}
public void RemoveUser(int tenant, Guid id)
@ -357,43 +362,48 @@ public class EFUserService : IUserService
public void RemoveUser(int tenant, Guid id, bool immediate)
{
using var tr = UserDbContext.Database.BeginTransaction();
var strategy = UserDbContext.Database.CreateExecutionStrategy();
UserDbContext.Acl.RemoveRange(UserDbContext.Acl.Where(r => r.Tenant == tenant && r.Subject == id));
UserDbContext.Subscriptions.RemoveRange(UserDbContext.Subscriptions.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()));
UserDbContext.SubscriptionMethods.RemoveRange(UserDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()));
UserDbContext.Photos.RemoveRange(UserDbContext.Photos.Where(r => r.Tenant == tenant && r.UserId == id));
var userGroups = UserDbContext.UserGroups.Where(r => r.Tenant == tenant && r.UserId == id);
var users = UserDbContext.Users.Where(r => r.Tenant == tenant && r.Id == id);
var userSecurity = UserDbContext.UserSecurity.Where(r => r.Tenant == tenant && r.UserId == id);
if (immediate)
strategy.Execute(() =>
{
UserDbContext.UserGroups.RemoveRange(userGroups);
UserDbContext.Users.RemoveRange(users);
UserDbContext.UserSecurity.RemoveRange(userSecurity);
}
else
{
foreach (var ug in userGroups)
using var tr = UserDbContext.Database.BeginTransaction();
UserDbContext.Acl.RemoveRange(UserDbContext.Acl.Where(r => r.Tenant == tenant && r.Subject == id));
UserDbContext.Subscriptions.RemoveRange(UserDbContext.Subscriptions.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()));
UserDbContext.SubscriptionMethods.RemoveRange(UserDbContext.SubscriptionMethods.Where(r => r.Tenant == tenant && r.Recipient == id.ToString()));
UserDbContext.Photos.RemoveRange(UserDbContext.Photos.Where(r => r.Tenant == tenant && r.UserId == id));
var userGroups = UserDbContext.UserGroups.Where(r => r.Tenant == tenant && r.UserId == id);
var users = UserDbContext.Users.Where(r => r.Tenant == tenant && r.Id == id);
var userSecurity = UserDbContext.UserSecurity.Where(r => r.Tenant == tenant && r.UserId == id);
if (immediate)
{
ug.Removed = true;
ug.LastModified = DateTime.UtcNow;
UserDbContext.UserGroups.RemoveRange(userGroups);
UserDbContext.Users.RemoveRange(users);
UserDbContext.UserSecurity.RemoveRange(userSecurity);
}
else
{
foreach (var ug in userGroups)
{
ug.Removed = true;
ug.LastModified = DateTime.UtcNow;
}
foreach (var u in users)
{
u.Removed = true;
u.Status = EmployeeStatus.Terminated;
u.TerminatedDate = DateTime.UtcNow;
u.LastModified = DateTime.UtcNow;
}
}
foreach (var u in users)
{
u.Removed = true;
u.Status = EmployeeStatus.Terminated;
u.TerminatedDate = DateTime.UtcNow;
u.LastModified = DateTime.UtcNow;
}
}
UserDbContext.SaveChanges();
UserDbContext.SaveChanges();
tr.Commit();
tr.Commit();
});
}
public void RemoveUserGroupRef(int tenant, Guid userId, Guid groupId, UserGroupRefType refType)
@ -403,26 +413,31 @@ public class EFUserService : IUserService
public void RemoveUserGroupRef(int tenant, Guid userId, Guid groupId, UserGroupRefType refType, bool immediate)
{
using var tr = UserDbContext.Database.BeginTransaction();
var strategy = UserDbContext.Database.CreateExecutionStrategy();
var userGroups = UserDbContext.UserGroups.Where(r => r.Tenant == tenant && r.UserId == userId && r.GroupId == groupId && r.RefType == refType);
if (immediate)
strategy.Execute(() =>
{
UserDbContext.UserGroups.RemoveRange(userGroups);
}
else
{
foreach (var u in userGroups)
using var tr = UserDbContext.Database.BeginTransaction();
var userGroups = UserDbContext.UserGroups.Where(r => r.Tenant == tenant && r.UserId == userId && r.GroupId == groupId && r.RefType == refType);
if (immediate)
{
u.LastModified = DateTime.UtcNow;
u.Removed = true;
UserDbContext.UserGroups.RemoveRange(userGroups);
}
}
var user = UserDbContext.Users.First(r => r.Tenant == tenant && r.Id == userId);
user.LastModified = DateTime.UtcNow;
UserDbContext.SaveChanges();
else
{
foreach (var u in userGroups)
{
u.LastModified = DateTime.UtcNow;
u.Removed = true;
}
}
var user = UserDbContext.Users.First(r => r.Tenant == tenant && r.Id == userId);
user.LastModified = DateTime.UtcNow;
UserDbContext.SaveChanges();
tr.Commit();
tr.Commit();
});
}
public Group SaveGroup(int tenant, Group group)
@ -468,26 +483,31 @@ public class EFUserService : IUserService
user.UserName = user.UserName.Trim();
user.Email = user.Email.Trim();
using var tx = UserDbContext.Database.BeginTransaction();
var any = GetUserQuery(tenant)
.Any(r => r.UserName == user.UserName && r.Id != user.Id && !r.Removed);
var strategy = UserDbContext.Database.CreateExecutionStrategy();
if (any)
strategy.Execute(() =>
{
throw new ArgumentOutOfRangeException("Duplicate username.");
}
using var tx = UserDbContext.Database.BeginTransaction();
var any = GetUserQuery(tenant)
.Any(r => r.UserName == user.UserName && r.Id != user.Id && !r.Removed);
any = GetUserQuery(tenant)
.Any(r => r.Email == user.Email && r.Id != user.Id && !r.Removed);
if (any)
{
throw new ArgumentOutOfRangeException("Duplicate username.");
}
if (any)
{
throw new ArgumentOutOfRangeException("Duplicate email.");
}
any = GetUserQuery(tenant)
.Any(r => r.Email == user.Email && r.Id != user.Id && !r.Removed);
UserDbContext.AddOrUpdate(r => r.Users, _mapper.Map<UserInfo, User>(user));
UserDbContext.SaveChanges();
tx.Commit();
if (any)
{
throw new ArgumentOutOfRangeException("Duplicate email.");
}
UserDbContext.AddOrUpdate(r => r.Users, _mapper.Map<UserInfo, User>(user));
UserDbContext.SaveChanges();
tx.Commit();
});
return user;
}
@ -499,17 +519,24 @@ public class EFUserService : IUserService
userGroupRef.LastModified = DateTime.UtcNow;
userGroupRef.Tenant = tenant;
using var tr = UserDbContext.Database.BeginTransaction();
var strategy = UserDbContext.Database.CreateExecutionStrategy();
var user = GetUserQuery(tenant).FirstOrDefault(a => a.Tenant == tenant && a.Id == userGroupRef.UserId);
if (user != null)
strategy.Execute(() =>
{
user.LastModified = userGroupRef.LastModified;
UserDbContext.AddOrUpdate(r => r.UserGroups, _mapper.Map<UserGroupRef, UserGroup>(userGroupRef));
}
using var tr = UserDbContext.Database.BeginTransaction();
var user = GetUserQuery(tenant).FirstOrDefault(a => a.Tenant == tenant && a.Id == userGroupRef.UserId);
if (user != null)
{
user.LastModified = userGroupRef.LastModified;
UserDbContext.AddOrUpdate(r => r.UserGroups, _mapper.Map<UserGroupRef, UserGroup>(userGroupRef));
}
UserDbContext.SaveChanges();
tr.Commit();
});
UserDbContext.SaveChanges();
tr.Commit();
return userGroupRef;
}
@ -533,34 +560,39 @@ public class EFUserService : IUserService
public void SetUserPhoto(int tenant, Guid id, byte[] photo)
{
using var tr = UserDbContext.Database.BeginTransaction();
var strategy = UserDbContext.Database.CreateExecutionStrategy();
var userPhoto = UserDbContext.Photos.FirstOrDefault(r => r.UserId == id && r.Tenant == tenant);
if (photo != null && photo.Length != 0)
strategy.Execute(() =>
{
if (userPhoto == null)
using var tr = UserDbContext.Database.BeginTransaction();
var userPhoto = UserDbContext.Photos.FirstOrDefault(r => r.UserId == id && r.Tenant == tenant);
if (photo != null && photo.Length != 0)
{
userPhoto = new UserPhoto
if (userPhoto == null)
{
Tenant = tenant,
UserId = id,
Photo = photo
};
userPhoto = new UserPhoto
{
Tenant = tenant,
UserId = id,
Photo = photo
};
}
else
{
userPhoto.Photo = photo;
}
UserDbContext.AddOrUpdate(r => r.Photos, userPhoto);
}
else
else if (userPhoto != null)
{
userPhoto.Photo = photo;
UserDbContext.Photos.Remove(userPhoto);
}
UserDbContext.AddOrUpdate(r => r.Photos, userPhoto);
}
else if (userPhoto != null)
{
UserDbContext.Photos.Remove(userPhoto);
}
UserDbContext.SaveChanges();
tr.Commit();
UserDbContext.SaveChanges();
tr.Commit();
});
}
private IQueryable<User> GetUserQuery(int tenant)

View File

@ -74,15 +74,15 @@ public class BaseDbContext : DbContext
switch (_provider)
{
case Provider.MySql:
optionsBuilder.UseMySql(ConnectionStringSettings.ConnectionString, ServerVersion, sqlOptions =>
optionsBuilder.UseMySql(ConnectionStringSettings.ConnectionString, ServerVersion, providerOptions =>
{
if (!string.IsNullOrEmpty(MigrateAssembly))
{
sqlOptions.MigrationsAssembly(MigrateAssembly);
providerOptions.MigrationsAssembly(MigrateAssembly);
}
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
// sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
providerOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
});
break;
case Provider.PostgreSql:

View File

@ -149,3 +149,4 @@ global using ProtoBuf;
global using Telegram.Bot;
global using static ASC.Security.Cryptography.EmailValidationKeyProvider;
global using ASC.Common.Data;

View File

@ -79,7 +79,7 @@ public class RegisterInstanceDao<T> : IRegisterInstanceDao<T> where T : IHostedS
public async Task<IEnumerable<InstanceRegistration>> GetAll()
{
return await _instanceRegistrationContext.InstanceRegistrations
.Where(x => x.WorkerTypeName == typeof(T).Name)
.Where(x => x.WorkerTypeName == typeof(T).GetFormattedName())
.ToListAsync();
}

View File

@ -51,7 +51,7 @@ public class RegisterInstanceManager<T> : IRegisterInstanceManager<T> where T :
var instance = registeredInstance ?? new InstanceRegistration
{
InstanceRegistrationId = instanceId,
WorkerTypeName = typeof(T).Name
WorkerTypeName = typeof(T).GetFormattedName()
};
instance.LastUpdated = DateTime.UtcNow;

View File

@ -24,7 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Core.Common.Hosting;
namespace ASC.Core.Common.Hosting;
[Singletone]
public class RegisterInstanceWorkerService<T> : BackgroundService where T : IHostedService
@ -33,7 +33,7 @@ public class RegisterInstanceWorkerService<T> : BackgroundService where T : IHos
private readonly IHostApplicationLifetime _applicationLifetime;
private readonly IServiceProvider _serviceProvider;
public static readonly string InstanceId =
$"{typeof(T).Name}_{DateTime.UtcNow.Ticks}";
$"{typeof(T).GetFormattedName()}_{DateTime.UtcNow.Ticks}";
public RegisterInstanceWorkerService(
ILogger<RegisterInstanceWorkerService<T>> logger,
@ -58,7 +58,7 @@ public class RegisterInstanceWorkerService<T> : BackgroundService where T : IHos
await registerInstanceService.Register(InstanceId);
await registerInstanceService.DeleteOrphanInstances();
_logger.InformationWorkingRunnging(DateTimeOffset.Now);
_logger.TraceWorkingRunnging(DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
@ -87,5 +87,6 @@ public class RegisterInstanceWorkerService<T> : BackgroundService where T : IHos
}
await base.StopAsync(cancellationToken);
}
}
}

View File

@ -31,8 +31,8 @@ internal static partial class RegisterInstanceWorkerServiceLogger
[LoggerMessage(Level = LogLevel.Trace, Message = "DbUpdateConcurrencyException: then updating {instanceName} at {time} time.")]
public static partial void TraceDbUpdateConcurrencyException(this ILogger logger, string instanceName, DateTimeOffset time);
[LoggerMessage(Level = LogLevel.Information, Message = "Worker running at: {time}")]
public static partial void InformationWorkingRunnging(this ILogger logger, DateTimeOffset time);
[LoggerMessage(Level = LogLevel.Trace, Message = "Worker running at: {time}")]
public static partial void TraceWorkingRunnging(this ILogger logger, DateTimeOffset time);
[LoggerMessage(Level = LogLevel.Information, Message = "UnRegister Instance {instanceName} running at: {time}.")]
public static partial void InformationUnRegister(this ILogger logger, string instanceName, DateTimeOffset time);

View File

@ -166,26 +166,34 @@ public class AccountLinker
public void RemoveProvider(string obj, string provider = null, string hashId = null)
{
using var tr = AccountLinkContext.Database.BeginTransaction();
var strategy = AccountLinkContext.Database.CreateExecutionStrategy();
var accountLinkQuery = AccountLinks
.Where(r => r.Id == obj);
if (!string.IsNullOrEmpty(provider))
strategy.Execute(() =>
{
accountLinkQuery = accountLinkQuery.Where(r => r.Provider == provider);
}
using var tr = AccountLinkContext.Database.BeginTransaction();
var accountLinkQuery = AccountLinks
.Where(r => r.Id == obj);
if (!string.IsNullOrEmpty(provider))
{
accountLinkQuery = accountLinkQuery.Where(r => r.Provider == provider);
}
if (!string.IsNullOrEmpty(hashId))
{
accountLinkQuery = accountLinkQuery.Where(r => r.UId == hashId);
}
var accountLink = accountLinkQuery.FirstOrDefault();
AccountLinks.Remove(accountLink);
AccountLinkContext.SaveChanges();
tr.Commit();
});
if (!string.IsNullOrEmpty(hashId))
{
accountLinkQuery = accountLinkQuery.Where(r => r.UId == hashId);
}
var accountLink = accountLinkQuery.FirstOrDefault();
AccountLinks.Remove(accountLink);
AccountLinkContext.SaveChanges();
tr.Commit();
AccountLinkerStorage.RemoveFromCache(obj);
}

View File

@ -98,57 +98,67 @@ public class FeedAggregateDataProvider
private void SaveFeedsPortion(IEnumerable<FeedRow> feeds, DateTime aggregatedDate)
{
using var tx = FeedDbContext.Database.BeginTransaction();
var strategy = FeedDbContext.Database.CreateExecutionStrategy();
foreach (var f in feeds)
strategy.Execute(() =>
{
if (0 >= f.Users.Count)
{
continue;
}
using var tx = FeedDbContext.Database.BeginTransaction();
var feedAggregate = _mapper.Map<FeedRow, FeedAggregate>(f);
feedAggregate.AggregateDate = aggregatedDate;
if (f.ClearRightsBeforeInsert)
foreach (var f in feeds)
{
var fu = FeedDbContext.FeedUsers.Where(r => r.FeedId == f.Id).FirstOrDefault();
if (fu != null)
if (0 >= f.Users.Count)
{
FeedDbContext.FeedUsers.Remove(fu);
continue;
}
var feedAggregate = _mapper.Map<FeedRow, FeedAggregate>(f);
feedAggregate.AggregateDate = aggregatedDate;
if (f.ClearRightsBeforeInsert)
{
var fu = FeedDbContext.FeedUsers.Where(r => r.FeedId == f.Id).FirstOrDefault();
if (fu != null)
{
FeedDbContext.FeedUsers.Remove(fu);
}
}
FeedDbContext.AddOrUpdate(r => r.FeedAggregates, feedAggregate);
foreach (var u in f.Users)
{
var feedUser = new FeedUsers
{
FeedId = f.Id,
UserId = u
};
FeedDbContext.AddOrUpdate(r => r.FeedUsers, feedUser);
}
}
FeedDbContext.AddOrUpdate(r => r.FeedAggregates, feedAggregate);
FeedDbContext.SaveChanges();
foreach (var u in f.Users)
{
var feedUser = new FeedUsers
{
FeedId = f.Id,
UserId = u
};
FeedDbContext.AddOrUpdate(r => r.FeedUsers, feedUser);
}
}
FeedDbContext.SaveChanges();
tx.Commit();
tx.Commit();
});
}
public void RemoveFeedAggregate(DateTime fromTime)
{
using var tx = FeedDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
var strategy = FeedDbContext.Database.CreateExecutionStrategy();
var aggregates = FeedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime);
FeedDbContext.FeedAggregates.RemoveRange(aggregates);
strategy.Execute(() =>
{
using var tx = FeedDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
var users = FeedDbContext.FeedUsers.Where(r => FeedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime).Any(a => a.Id == r.FeedId));
FeedDbContext.FeedUsers.RemoveRange(users);
var aggregates = FeedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime);
FeedDbContext.FeedAggregates.RemoveRange(aggregates);
tx.Commit();
var users = FeedDbContext.FeedUsers.Where(r => FeedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime).Any(a => a.Id == r.FeedId));
FeedDbContext.FeedUsers.RemoveRange(users);
tx.Commit();
});
}
public List<FeedResultItem> GetFeeds(FeedApiFilter filter)
@ -273,17 +283,22 @@ public class FeedAggregateDataProvider
public void RemoveFeedItem(string id)
{
using var tx = FeedDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
var strategy = FeedDbContext.Database.CreateExecutionStrategy();
var aggregates = FeedDbContext.FeedAggregates.Where(r => r.Id == id);
FeedDbContext.FeedAggregates.RemoveRange(aggregates);
strategy.Execute(() =>
{
using var tx = FeedDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
var users = FeedDbContext.FeedUsers.Where(r => r.FeedId == id);
FeedDbContext.FeedUsers.RemoveRange(users);
var aggregates = FeedDbContext.FeedAggregates.Where(r => r.Id == id);
FeedDbContext.FeedAggregates.RemoveRange(aggregates);
FeedDbContext.SaveChanges();
var users = FeedDbContext.FeedUsers.Where(r => r.FeedId == id);
FeedDbContext.FeedUsers.RemoveRange(users);
tx.Commit();
FeedDbContext.SaveChanges();
tx.Commit();
});
}
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Microsoft.EntityFrameworkCore;
namespace ASC.IPSecurity;
[Scope]
@ -52,21 +54,26 @@ public class IPRestrictionsRepository
public List<string> Save(IEnumerable<string> ips, int tenant)
{
using var tx = TenantDbContext.Database.BeginTransaction();
var strategy = TenantDbContext.Database.CreateExecutionStrategy();
var restrictions = TenantDbContext.TenantIpRestrictions.Where(r => r.Tenant == tenant).ToList();
TenantDbContext.TenantIpRestrictions.RemoveRange(restrictions);
var ipsList = ips.Select(r => new TenantIpRestrictions
strategy.Execute(() =>
{
Tenant = tenant,
Ip = r
using var tx = TenantDbContext.Database.BeginTransaction();
var restrictions = TenantDbContext.TenantIpRestrictions.Where(r => r.Tenant == tenant).ToList();
TenantDbContext.TenantIpRestrictions.RemoveRange(restrictions);
var ipsList = ips.Select(r => new TenantIpRestrictions
{
Tenant = tenant,
Ip = r
});
TenantDbContext.TenantIpRestrictions.AddRange(ipsList);
tx.Commit();
});
TenantDbContext.TenantIpRestrictions.AddRange(ipsList);
tx.Commit();
return ips.ToList();
}
}

View File

@ -106,51 +106,56 @@ public class MessagesRepository : IDisposable
return;
}
using var scope = _serviceScopeFactory.CreateScope();
using var ef = scope.ServiceProvider.GetService<DbContextManager<MessagesContext>>().Get("messages");
using var tx = ef.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
var dict = new Dictionary<string, ClientInfo>();
foreach (var message in events)
{
if (!string.IsNullOrEmpty(message.UAHeader))
{
try
{
ClientInfo clientInfo;
if (dict.TryGetValue(message.UAHeader, out clientInfo))
{
}
else
{
_parser = _parser ?? Parser.GetDefault();
clientInfo = _parser.Parse(message.UAHeader);
dict.Add(message.UAHeader, clientInfo);
}
if (clientInfo != null)
{
message.Browser = GetBrowser(clientInfo);
message.Platform = GetPlatform(clientInfo);
}
}
catch (Exception e)
{
_logger.ErrorFlushCache(message.Id, e);
}
}
// messages with action code < 2000 are related to login-history
if ((int)message.Action >= 2000)
{
AddAuditEvent(message, ef);
}
}
tx.Commit();
using var scope = _serviceScopeFactory.CreateScope();
using var ef = scope.ServiceProvider.GetService<DbContextManager<MessagesContext>>().Get("messages");
var strategy = ef.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
using var tx = ef.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
var dict = new Dictionary<string, ClientInfo>();
foreach (var message in events)
{
if (!string.IsNullOrEmpty(message.UAHeader))
{
try
{
ClientInfo clientInfo;
if (dict.TryGetValue(message.UAHeader, out clientInfo))
{
}
else
{
_parser = _parser ?? Parser.GetDefault();
clientInfo = _parser.Parse(message.UAHeader);
dict.Add(message.UAHeader, clientInfo);
}
if (clientInfo != null)
{
message.Browser = GetBrowser(clientInfo);
message.Platform = GetPlatform(clientInfo);
}
}
catch (Exception e)
{
_logger.ErrorFlushCache(message.Id, e);
}
}
// messages with action code < 2000 are related to login-history
if ((int)message.Action >= 2000)
{
AddAuditEvent(message, ef);
}
}
tx.Commit();
});
}
private void AddLoginEvent(EventMessage message, MessagesContext dbContext)

View File

@ -49,29 +49,35 @@ public class DbWorker
var _mapper = scope.ServiceProvider.GetRequiredService<IMapper>();
using var dbContext = scope.ServiceProvider.GetService<DbContextManager<NotifyDbContext>>().Get(_dbid);
using var tx = dbContext.Database.BeginTransaction(IsolationLevel.ReadCommitted);
var notifyQueue = _mapper.Map<NotifyMessage, NotifyQueue>(m);
var strategy = dbContext.Database.CreateExecutionStrategy();
notifyQueue = dbContext.NotifyQueue.Add(notifyQueue).Entity;
dbContext.SaveChanges();
var id = notifyQueue.NotifyId;
var info = new NotifyInfo
strategy.Execute(() =>
{
NotifyId = id,
State = 0,
Attempts = 0,
ModifyDate = DateTime.UtcNow,
Priority = m.Priority
};
using var tx = dbContext.Database.BeginTransaction(IsolationLevel.ReadCommitted);
dbContext.NotifyInfo.Add(info);
dbContext.SaveChanges();
var notifyQueue = _mapper.Map<NotifyMessage, NotifyQueue>(m);
tx.Commit();
notifyQueue = dbContext.NotifyQueue.Add(notifyQueue).Entity;
dbContext.SaveChanges();
var id = notifyQueue.NotifyId;
var info = new NotifyInfo
{
NotifyId = id,
State = 0,
Attempts = 0,
ModifyDate = DateTime.UtcNow,
Priority = m.Priority
};
dbContext.NotifyInfo.Add(info);
dbContext.SaveChanges();
tx.Commit();
});
return 1;
}
@ -84,8 +90,7 @@ public class DbWorker
var _mapper = scope.ServiceProvider.GetRequiredService<IMapper>();
using var dbContext = scope.ServiceProvider.GetService<DbContextManager<NotifyDbContext>>().Get(_dbid);
using var tx = dbContext.Database.BeginTransaction();
var q = dbContext.NotifyQueue
.Join(dbContext.NotifyInfo, r => r.NotifyId, r => r.NotifyId, (queue, info) => new { queue, info })
.Where(r => r.info.State == (int)MailSendingState.NotSended || r.info.State == (int)MailSendingState.Error && r.info.ModifyDate < DateTime.UtcNow - TimeSpan.Parse(_notifyServiceCfg.Process.AttemptsInterval))
@ -113,15 +118,22 @@ public class DbWorker
return res;
});
var info = dbContext.NotifyInfo.Where(r => messages.Keys.Any(a => a == r.NotifyId)).ToList();
var strategy = dbContext.Database.CreateExecutionStrategy();
foreach (var i in info)
strategy.Execute(() =>
{
i.State = (int)MailSendingState.Sending;
}
using var tx = dbContext.Database.BeginTransaction();
dbContext.SaveChanges();
tx.Commit();
var info = dbContext.NotifyInfo.Where(r => messages.Keys.Any(a => a == r.NotifyId)).ToList();
foreach (var i in info)
{
i.State = (int)MailSendingState.Sending;
}
dbContext.SaveChanges();
tx.Commit();
});
return messages;
}
@ -132,16 +144,21 @@ public class DbWorker
using var scope = _serviceScopeFactory.CreateScope();
using var dbContext = scope.ServiceProvider.GetService<DbContextManager<NotifyDbContext>>().Get(_dbid);
var tr = dbContext.Database.BeginTransaction();
var info = dbContext.NotifyInfo.Where(r => r.State == 1).ToList();
var strategy = dbContext.Database.CreateExecutionStrategy();
foreach (var i in info)
strategy.Execute(() =>
{
i.State = 0;
}
var tr = dbContext.Database.BeginTransaction();
var info = dbContext.NotifyInfo.Where(r => r.State == 1).ToList();
dbContext.SaveChanges();
tr.Commit();
foreach (var i in info)
{
i.State = 0;
}
dbContext.SaveChanges();
tr.Commit();
});
}
public void SetState(int id, MailSendingState result)
@ -150,38 +167,43 @@ public class DbWorker
using var dbContext = scope.ServiceProvider.GetService<DbContextManager<NotifyDbContext>>().Get(_dbid);
using var tx = dbContext.Database.BeginTransaction();
if (result == MailSendingState.Sended)
var strategy = dbContext.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
var d = dbContext.NotifyInfo.Where(r => r.NotifyId == id).FirstOrDefault();
dbContext.NotifyInfo.Remove(d);
dbContext.SaveChanges();
}
else
{
if (result == MailSendingState.Error)
if (result == MailSendingState.Sended)
{
var attempts = dbContext.NotifyInfo.Where(r => r.NotifyId == id).Select(r => r.Attempts).FirstOrDefault();
if (_notifyServiceCfg.Process.MaxAttempts <= attempts + 1)
var d = dbContext.NotifyInfo.Where(r => r.NotifyId == id).FirstOrDefault();
dbContext.NotifyInfo.Remove(d);
dbContext.SaveChanges();
}
else
{
if (result == MailSendingState.Error)
{
result = MailSendingState.FatalError;
var attempts = dbContext.NotifyInfo.Where(r => r.NotifyId == id).Select(r => r.Attempts).FirstOrDefault();
if (_notifyServiceCfg.Process.MaxAttempts <= attempts + 1)
{
result = MailSendingState.FatalError;
}
}
var info = dbContext.NotifyInfo
.Where(r => r.NotifyId == id)
.ToList();
foreach (var i in info)
{
i.State = (int)result;
i.Attempts += 1;
i.ModifyDate = DateTime.UtcNow;
}
dbContext.SaveChanges();
}
var info = dbContext.NotifyInfo
.Where(r => r.NotifyId == id)
.ToList();
foreach (var i in info)
{
i.State = (int)result;
i.Attempts += 1;
i.ModifyDate = DateTime.UtcNow;
}
dbContext.SaveChanges();
}
tx.Commit();
tx.Commit();
});
}
}

View File

@ -78,18 +78,23 @@ public class NotifyCleanerService : BackgroundService
using var scope = _scopeFactory.CreateScope();
using var dbContext = scope.ServiceProvider.GetService<DbContextManager<NotifyDbContext>>().Get(_notifyServiceCfg.ConnectionStringName);
using var tx = dbContext.Database.BeginTransaction();
var info = dbContext.NotifyInfo.Where(r => r.ModifyDate < date && r.State == 4).ToList();
var queue = dbContext.NotifyQueue.Where(r => r.CreationDate < date).ToList();
dbContext.NotifyInfo.RemoveRange(info);
dbContext.NotifyQueue.RemoveRange(queue);
var strategy = dbContext.Database.CreateExecutionStrategy();
dbContext.SaveChanges();
tx.Commit();
strategy.Execute(() =>
{
using var tx = dbContext.Database.BeginTransaction();
_logger.InformationClearNotifyMessages(info.Count, queue.Count);
var info = dbContext.NotifyInfo.Where(r => r.ModifyDate < date && r.State == 4).ToList();
var queue = dbContext.NotifyQueue.Where(r => r.CreationDate < date).ToList();
dbContext.NotifyInfo.RemoveRange(info);
dbContext.NotifyQueue.RemoveRange(queue);
dbContext.SaveChanges();
tx.Commit();
_logger.InformationClearNotifyMessages(info.Count, queue.Count);
});
}
catch (ThreadAbortException)
{

View File

@ -390,67 +390,73 @@ internal class FileDao : AbstractDao, IFileDao<int>
lock (_syncRoot)
{
using var tx = FilesDbContext.Database.BeginTransaction();
if (file.Id == default)
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
file.Id = FilesDbContext.Files.Any() ? FilesDbContext.Files.Max(r => r.Id) + 1 : 1;
file.Version = 1;
file.VersionGroup = 1;
isNew = true;
}
using var tx = FilesDbContext.Database.BeginTransaction();
file.Title = Global.ReplaceInvalidCharsAndTruncate(file.Title);
//make lowerCase
file.Title = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetFileExtension(file.Title));
if (file.Id == default)
{
file.Id = FilesDbContext.Files.Any() ? FilesDbContext.Files.Max(r => r.Id) + 1 : 1;
file.Version = 1;
file.VersionGroup = 1;
isNew = true;
}
file.ModifiedBy = _authContext.CurrentAccount.ID;
file.ModifiedOn = _tenantUtil.DateTimeNow();
if (file.CreateBy == default)
{
file.CreateBy = _authContext.CurrentAccount.ID;
}
file.Title = Global.ReplaceInvalidCharsAndTruncate(file.Title);
//make lowerCase
file.Title = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetFileExtension(file.Title));
if (file.CreateOn == default)
{
file.CreateOn = _tenantUtil.DateTimeNow();
}
file.ModifiedBy = _authContext.CurrentAccount.ID;
file.ModifiedOn = _tenantUtil.DateTimeNow();
if (file.CreateBy == default)
{
file.CreateBy = _authContext.CurrentAccount.ID;
}
var toUpdate = FilesDbContext.Files
.FirstOrDefault(r => r.Id == file.Id && r.CurrentVersion && r.TenantId == TenantID);
if (file.CreateOn == default)
{
file.CreateOn = _tenantUtil.DateTimeNow();
}
if (toUpdate != null)
{
toUpdate.CurrentVersion = false;
var toUpdate = FilesDbContext.Files
.FirstOrDefault(r => r.Id == file.Id && r.CurrentVersion && r.TenantId == TenantID);
if (toUpdate != null)
{
toUpdate.CurrentVersion = false;
FilesDbContext.SaveChanges();
}
toInsert = new DbFile
{
Id = file.Id,
Version = file.Version,
VersionGroup = file.VersionGroup,
CurrentVersion = true,
ParentId = file.ParentId,
Title = file.Title,
ContentLength = file.ContentLength,
Category = (int)file.FilterType,
CreateBy = file.CreateBy,
CreateOn = _tenantUtil.DateTimeToUtc(file.CreateOn),
ModifiedBy = file.ModifiedBy,
ModifiedOn = _tenantUtil.DateTimeToUtc(file.ModifiedOn),
ConvertedType = file.ConvertedType,
Comment = file.Comment,
Encrypted = file.Encrypted,
Forcesave = file.Forcesave,
ThumbnailStatus = file.ThumbnailStatus,
TenantId = TenantID
};
FilesDbContext.AddOrUpdate(r => r.Files, toInsert);
FilesDbContext.SaveChanges();
}
toInsert = new DbFile
{
Id = file.Id,
Version = file.Version,
VersionGroup = file.VersionGroup,
CurrentVersion = true,
ParentId = file.ParentId,
Title = file.Title,
ContentLength = file.ContentLength,
Category = (int)file.FilterType,
CreateBy = file.CreateBy,
CreateOn = _tenantUtil.DateTimeToUtc(file.CreateOn),
ModifiedBy = file.ModifiedBy,
ModifiedOn = _tenantUtil.DateTimeToUtc(file.ModifiedOn),
ConvertedType = file.ConvertedType,
Comment = file.Comment,
Encrypted = file.Encrypted,
Forcesave = file.Forcesave,
ThumbnailStatus = file.ThumbnailStatus,
TenantId = TenantID
};
FilesDbContext.AddOrUpdate(r => r.Files, toInsert);
FilesDbContext.SaveChanges();
tx.Commit();
tx.Commit();
});
file.PureTitle = file.Title;
@ -554,46 +560,51 @@ internal class FileDao : AbstractDao, IFileDao<int>
List<int> parentFoldersIds;
lock (_syncRoot)
{
using var tx = FilesDbContext.Database.BeginTransaction();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
file.Title = Global.ReplaceInvalidCharsAndTruncate(file.Title);
//make lowerCase
file.Title = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetFileExtension(file.Title));
file.ModifiedBy = _authContext.CurrentAccount.ID;
file.ModifiedOn = _tenantUtil.DateTimeNow();
if (file.CreateBy == default)
strategy.Execute(() =>
{
file.CreateBy = _authContext.CurrentAccount.ID;
}
using var tx = FilesDbContext.Database.BeginTransaction();
if (file.CreateOn == default)
{
file.CreateOn = _tenantUtil.DateTimeNow();
}
file.Title = Global.ReplaceInvalidCharsAndTruncate(file.Title);
//make lowerCase
file.Title = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetFileExtension(file.Title));
toUpdate = FilesDbContext.Files
.FirstOrDefault(r => r.Id == file.Id && r.Version == file.Version && r.TenantId == TenantID);
file.ModifiedBy = _authContext.CurrentAccount.ID;
file.ModifiedOn = _tenantUtil.DateTimeNow();
if (file.CreateBy == default)
{
file.CreateBy = _authContext.CurrentAccount.ID;
}
toUpdate.Version = file.Version;
toUpdate.VersionGroup = file.VersionGroup;
toUpdate.ParentId = file.ParentId;
toUpdate.Title = file.Title;
toUpdate.ContentLength = file.ContentLength;
toUpdate.Category = (int)file.FilterType;
toUpdate.CreateBy = file.CreateBy;
toUpdate.CreateOn = _tenantUtil.DateTimeToUtc(file.CreateOn);
toUpdate.ModifiedBy = file.ModifiedBy;
toUpdate.ModifiedOn = _tenantUtil.DateTimeToUtc(file.ModifiedOn);
toUpdate.ConvertedType = file.ConvertedType;
toUpdate.Comment = file.Comment;
toUpdate.Encrypted = file.Encrypted;
toUpdate.Forcesave = file.Forcesave;
toUpdate.ThumbnailStatus = file.ThumbnailStatus;
if (file.CreateOn == default)
{
file.CreateOn = _tenantUtil.DateTimeNow();
}
FilesDbContext.SaveChanges();
toUpdate = FilesDbContext.Files
.FirstOrDefault(r => r.Id == file.Id && r.Version == file.Version && r.TenantId == TenantID);
tx.Commit();
toUpdate.Version = file.Version;
toUpdate.VersionGroup = file.VersionGroup;
toUpdate.ParentId = file.ParentId;
toUpdate.Title = file.Title;
toUpdate.ContentLength = file.ContentLength;
toUpdate.Category = (int)file.FilterType;
toUpdate.CreateBy = file.CreateBy;
toUpdate.CreateOn = _tenantUtil.DateTimeToUtc(file.CreateOn);
toUpdate.ModifiedBy = file.ModifiedBy;
toUpdate.ModifiedOn = _tenantUtil.DateTimeToUtc(file.ModifiedOn);
toUpdate.ConvertedType = file.ConvertedType;
toUpdate.Comment = file.Comment;
toUpdate.Encrypted = file.Encrypted;
toUpdate.Forcesave = file.Forcesave;
toUpdate.ThumbnailStatus = file.ThumbnailStatus;
FilesDbContext.SaveChanges();
tx.Commit();
});
file.PureTitle = file.Title;
@ -706,54 +717,59 @@ internal class FileDao : AbstractDao, IFileDao<int>
private async Task internalDeleteFileAsync(int fileId, bool deleteFolder)
{
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
var fromFolders = Query(FilesDbContext.Files)
.Where(r => r.Id == fileId)
.Select(a => a.ParentId)
.Distinct()
.AsAsyncEnumerable();
var toDeleteLinks = Query(FilesDbContext.TagLink).Where(r => r.EntryId == fileId.ToString() && r.EntryType == FileEntryType.File);
FilesDbContext.RemoveRange(await toDeleteLinks.ToListAsync());
var toDeleteFiles = Query(FilesDbContext.Files).Where(r => r.Id == fileId);
var toDeleteFile = await toDeleteFiles.FirstOrDefaultAsync(r => r.CurrentVersion).ConfigureAwait(false);
foreach (var d in toDeleteFiles)
await strategy.ExecuteAsync(async () =>
{
await _factoryIndexer.DeleteAsync(d).ConfigureAwait(false);
}
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);
FilesDbContext.RemoveRange(await toDeleteFiles.ToListAsync());
var fromFolders = Query(FilesDbContext.Files)
.Where(r => r.Id == fileId)
.Select(a => a.ParentId)
.Distinct()
.AsAsyncEnumerable();
var tagsToRemove = Query(FilesDbContext.Tag)
.Where(r => !Query(FilesDbContext.TagLink).Any(a => a.TagId == r.Id));
var toDeleteLinks = Query(FilesDbContext.TagLink).Where(r => r.EntryId == fileId.ToString() && r.EntryType == FileEntryType.File);
FilesDbContext.RemoveRange(await toDeleteLinks.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var toDeleteFiles = Query(FilesDbContext.Files).Where(r => r.Id == fileId);
var toDeleteFile = await toDeleteFiles.FirstOrDefaultAsync(r => r.CurrentVersion).ConfigureAwait(false);
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => r.EntryId == fileId.ToString())
.Where(r => r.EntryType == FileEntryType.File);
foreach (var d in toDeleteFiles)
{
await _factoryIndexer.DeleteAsync(d).ConfigureAwait(false);
}
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.RemoveRange(await toDeleteFiles.ToListAsync());
await tx.CommitAsync().ConfigureAwait(false);
var tagsToRemove = Query(FilesDbContext.Tag)
.Where(r => !Query(FilesDbContext.TagLink).Any(a => a.TagId == r.Id));
var forEachTask = fromFolders.ForEachAwaitAsync(async folderId => await RecalculateFilesCountAsync(folderId).ConfigureAwait(false)).ConfigureAwait(false);
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
if (deleteFolder)
{
await DeleteFolderAsync(fileId);
}
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => r.EntryId == fileId.ToString())
.Where(r => r.EntryType == FileEntryType.File);
if (toDeleteFile != null)
{
await _factoryIndexer.DeleteAsync(toDeleteFile).ConfigureAwait(false);
}
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await forEachTask;
await tx.CommitAsync().ConfigureAwait(false);
var forEachTask = fromFolders.ForEachAwaitAsync(async folderId => await RecalculateFilesCountAsync(folderId).ConfigureAwait(false)).ConfigureAwait(false);
if (deleteFolder)
{
await DeleteFolderAsync(fileId);
}
if (toDeleteFile != null)
{
await _factoryIndexer.DeleteAsync(toDeleteFile).ConfigureAwait(false);
}
await forEachTask;
});
}
public Task<bool> IsExistAsync(string title, object folderId)
@ -807,9 +823,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
var trashIdTask = _globalFolder.GetFolderTrashAsync<int>(_daoFactory);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var fromFolders = await Query(FilesDbContext.Files)
var fromFolders = await Query(FilesDbContext.Files)
.Where(r => r.Id == fileId)
.Select(a => a.ParentId)
.Distinct()
@ -817,33 +831,42 @@ internal class FileDao : AbstractDao, IFileDao<int>
.ToListAsync()
.ConfigureAwait(false);
toUpdate = await Query(FilesDbContext.Files)
.Where(r => r.Id == fileId)
.ToListAsync()
.ConfigureAwait(false);
toUpdate = await Query(FilesDbContext.Files)
.Where(r => r.Id == fileId)
.ToListAsync()
.ConfigureAwait(false);
foreach (var f in toUpdate)
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
f.ParentId = toFolderId;
var trashId = await trashIdTask;
if (trashId.Equals(toFolderId))
foreach (var f in toUpdate)
{
f.ModifiedBy = _authContext.CurrentAccount.ID;
f.ModifiedOn = DateTime.UtcNow;
f.ParentId = toFolderId;
var trashId = await trashIdTask;
if (trashId.Equals(toFolderId))
{
f.ModifiedBy = _authContext.CurrentAccount.ID;
f.ModifiedOn = DateTime.UtcNow;
}
}
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
foreach (var f in fromFolders)
{
await RecalculateFilesCountAsync(f).ConfigureAwait(false);
}
await RecalculateFilesCountAsync(toFolderId).ConfigureAwait(false);
}
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
foreach (var f in fromFolders)
{
await RecalculateFilesCountAsync(f).ConfigureAwait(false);
}
await RecalculateFilesCountAsync(toFolderId).ConfigureAwait(false);
}
});
var parentFoldersTask =
FilesDbContext.Tree
@ -992,29 +1015,34 @@ internal class FileDao : AbstractDao, IFileDao<int>
public async Task ContinueVersionAsync(int fileId, int fileVersion)
{
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
var versionGroup = await Query(FilesDbContext.Files)
.AsNoTracking()
.Where(r => r.Id == fileId)
.Where(r => r.Version == fileVersion)
.Select(r => r.VersionGroup)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
var toUpdate = Query(FilesDbContext.Files)
.Where(r => r.Id == fileId)
.Where(r => r.Version > fileVersion)
.Where(r => r.VersionGroup > versionGroup);
foreach (var f in toUpdate)
await strategy.ExecuteAsync(async () =>
{
f.VersionGroup -= 1;
}
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var versionGroup = await Query(FilesDbContext.Files)
.AsNoTracking()
.Where(r => r.Id == fileId)
.Where(r => r.Version == fileVersion)
.Select(r => r.VersionGroup)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
var toUpdate = Query(FilesDbContext.Files)
.Where(r => r.Id == fileId)
.Where(r => r.Version > fileVersion)
.Where(r => r.VersionGroup > versionGroup);
foreach (var f in toUpdate)
{
f.VersionGroup -= 1;
}
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
});
}
public bool UseTrashForRemove(File<int> file)

View File

@ -303,6 +303,32 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
}
public async Task<int> InternalSaveFolderAsync(Folder<int> folder, IDbContextTransaction transaction)
{
var folderId = folder.Id;
if (transaction == null)
{
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
using var tx = await FilesDbContext.Database.BeginTransactionAsync();
folderId = await InternalSaveFolderToDbAsync(folder);
await tx.CommitAsync().ConfigureAwait(false);
});
}
else
{
folderId = await InternalSaveFolderToDbAsync(folder);
}
//FactoryIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, folder));
return folderId;
}
public async Task<int> InternalSaveFolderToDbAsync(Folder<int> folder)
{
folder.Title = Global.ReplaceInvalidCharsAndTruncate(folder.Title);
@ -320,8 +346,6 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
var isnew = false;
var tx = transaction ?? FilesDbContext.Database.BeginTransaction();
if (folder.Id != default && await IsExistAsync(folder.Id).ConfigureAwait(false))
{
var toUpdate = await Query(FilesDbContext.Folders)
@ -399,19 +423,13 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
}
if (transaction == null)
{
await tx.CommitAsync().ConfigureAwait(false);
tx.Dispose();
}
if (isnew)
{
await RecalculateFoldersCountAsync(folder.Id).ConfigureAwait(false);
}
//FactoryIndexer.IndexAsync(FoldersWrapper.GetFolderWrapper(ServiceProvider, folder));
return folder.Id;
}
private Task<bool> IsExistAsync(int folderId)
@ -432,66 +450,70 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
private async Task InternalDeleteFolderAsync(int id)
{
using var tx = FilesDbContext.Database.BeginTransaction();
var subfolders =
await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.ParentId == id)
.Select(r => r.FolderId)
.ToListAsync().ConfigureAwait(false);
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
if (!subfolders.Contains(id))
await strategy.ExecuteAsync(async () =>
{
subfolders.Add(id); // chashed folder_tree
}
using var tx = await FilesDbContext.Database.BeginTransactionAsync();
var subfolders =
await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.ParentId == id)
.Select(r => r.FolderId)
.ToListAsync().ConfigureAwait(false);
var parent = await Query(FilesDbContext.Folders)
.Where(r => r.Id == id)
.Select(r => r.ParentId)
.FirstOrDefaultAsync().ConfigureAwait(false);
if (!subfolders.Contains(id))
{
subfolders.Add(id); // chashed folder_tree
}
var folderToDelete = await Query(FilesDbContext.Folders).Where(r => subfolders.Contains(r.Id)).ToListAsync();
FilesDbContext.Folders.RemoveRange(folderToDelete);
var parent = await Query(FilesDbContext.Folders)
.Where(r => r.Id == id)
.Select(r => r.ParentId)
.FirstOrDefaultAsync().ConfigureAwait(false);
foreach (var f in folderToDelete)
{
await _factoryIndexer.DeleteAsync(f).ConfigureAwait(false);
}
var folderToDelete = await Query(FilesDbContext.Folders).Where(r => subfolders.Contains(r.Id)).ToListAsync();
FilesDbContext.Folders.RemoveRange(folderToDelete);
var treeToDelete = await FilesDbContext.Tree.AsQueryable().Where(r => subfolders.Contains(r.FolderId)).ToListAsync();
FilesDbContext.Tree.RemoveRange(treeToDelete);
foreach (var f in folderToDelete)
{
await _factoryIndexer.DeleteAsync(f).ConfigureAwait(false);
}
var subfoldersStrings = subfolders.Select(r => r.ToString()).ToList();
var linkToDelete = await Query(FilesDbContext.TagLink)
.Where(r => subfoldersStrings.Contains(r.EntryId))
.Where(r => r.EntryType == FileEntryType.Folder)
.ToListAsync();
FilesDbContext.TagLink.RemoveRange(linkToDelete);
var treeToDelete = await FilesDbContext.Tree.AsQueryable().Where(r => subfolders.Contains(r.FolderId)).ToListAsync();
FilesDbContext.Tree.RemoveRange(treeToDelete);
var tagsToRemove = await Query(FilesDbContext.Tag)
.Where(r => !Query(FilesDbContext.TagLink).Any(a => a.TagId == r.Id))
.ToListAsync();
FilesDbContext.Tag.RemoveRange(tagsToRemove);
var securityToDelete = await Query(FilesDbContext.Security)
var subfoldersStrings = subfolders.Select(r => r.ToString()).ToList();
var linkToDelete = await Query(FilesDbContext.TagLink)
.Where(r => subfoldersStrings.Contains(r.EntryId))
.Where(r => r.EntryType == FileEntryType.Folder)
.ToListAsync();
FilesDbContext.TagLink.RemoveRange(linkToDelete);
FilesDbContext.Security.RemoveRange(securityToDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = await Query(FilesDbContext.Tag)
.Where(r => !Query(FilesDbContext.TagLink).Any(a => a.TagId == r.Id))
.ToListAsync();
var bunchToDelete = await Query(FilesDbContext.BunchObjects)
.Where(r => r.LeftNode == id.ToString())
.ToListAsync();
FilesDbContext.Tag.RemoveRange(tagsToRemove);
FilesDbContext.RemoveRange(bunchToDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var securityToDelete = await Query(FilesDbContext.Security)
.Where(r => subfoldersStrings.Contains(r.EntryId))
.Where(r => r.EntryType == FileEntryType.Folder)
.ToListAsync();
await tx.CommitAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(securityToDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await RecalculateFoldersCountAsync(parent).ConfigureAwait(false);
var bunchToDelete = await Query(FilesDbContext.BunchObjects)
.Where(r => r.LeftNode == id.ToString())
.ToListAsync();
FilesDbContext.RemoveRange(bunchToDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
await RecalculateFoldersCountAsync(parent).ConfigureAwait(false);
});
//FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = id });
}
@ -513,86 +535,93 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
public async Task<int> MoveFolderAsync(int folderId, int toFolderId, CancellationToken? cancellationToken)
{
using (var tx = FilesDbContext.Database.BeginTransaction())
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var folder = await GetFolderAsync(folderId).ConfigureAwait(false);
if (folder.FolderType != FolderType.DEFAULT)
using (var tx = await FilesDbContext.Database.BeginTransactionAsync())
{
throw new ArgumentException("It is forbidden to move the System folder.", nameof(folderId));
}
var folder = await GetFolderAsync(folderId).ConfigureAwait(false);
var recalcFolders = new List<int> { toFolderId };
var parent = await FilesDbContext.Folders
.AsQueryable()
.Where(r => r.Id == folderId)
.Select(r => r.ParentId)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
if (parent != 0 && !recalcFolders.Contains(parent))
{
recalcFolders.Add(parent);
}
var toUpdate = await Query(FilesDbContext.Folders)
.Where(r => r.Id == folderId)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
toUpdate.ParentId = toFolderId;
toUpdate.ModifiedOn = DateTime.UtcNow;
toUpdate.ModifiedBy = _authContext.CurrentAccount.ID;
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var subfolders = await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.ParentId == folderId)
.ToDictionaryAsync(r => r.FolderId, r => r.Level)
.ConfigureAwait(false);
var toDelete = await FilesDbContext.Tree
.AsQueryable()
.Where(r => subfolders.ContainsKey(r.FolderId) && !subfolders.ContainsKey(r.ParentId))
.ToListAsync();
FilesDbContext.Tree.RemoveRange(toDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var toInsert = await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.FolderId == toFolderId)
.OrderBy(r => r.Level)
.ToListAsync()
.ConfigureAwait(false);
foreach (var subfolder in subfolders)
{
foreach (var f in toInsert)
if (folder.FolderType != FolderType.DEFAULT)
{
var newTree = new DbFolderTree
throw new ArgumentException("It is forbidden to move the System folder.", nameof(folderId));
}
var recalcFolders = new List<int> { toFolderId };
var parent = await FilesDbContext.Folders
.AsQueryable()
.Where(r => r.Id == folderId)
.Select(r => r.ParentId)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
if (parent != 0 && !recalcFolders.Contains(parent))
{
recalcFolders.Add(parent);
}
var toUpdate = await Query(FilesDbContext.Folders)
.Where(r => r.Id == folderId)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
toUpdate.ParentId = toFolderId;
toUpdate.ModifiedOn = DateTime.UtcNow;
toUpdate.ModifiedBy = _authContext.CurrentAccount.ID;
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var subfolders = await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.ParentId == folderId)
.ToDictionaryAsync(r => r.FolderId, r => r.Level)
.ConfigureAwait(false);
#pragma warning disable CA1841 // Prefer Dictionary.Contains methods
var toDelete = await FilesDbContext.Tree
.AsQueryable()
.Where(r => subfolders.Keys.Contains(r.FolderId) && !subfolders.Keys.Contains(r.ParentId))
.ToListAsync();
#pragma warning restore CA1841 // Prefer Dictionary.Contains methods
FilesDbContext.Tree.RemoveRange(toDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var toInsert = await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.FolderId == toFolderId)
.OrderBy(r => r.Level)
.ToListAsync()
.ConfigureAwait(false);
foreach (var subfolder in subfolders)
{
foreach (var f in toInsert)
{
FolderId = subfolder.Key,
ParentId = f.ParentId,
Level = subfolder.Value + 1 + f.Level
};
await FilesDbContext.AddOrUpdateAsync(r => r.Tree, newTree).ConfigureAwait(false);
var newTree = new DbFolderTree
{
FolderId = subfolder.Key,
ParentId = f.ParentId,
Level = subfolder.Value + 1 + f.Level
};
await FilesDbContext.AddOrUpdateAsync(r => r.Tree, newTree).ConfigureAwait(false);
}
}
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
foreach (var e in recalcFolders)
{
await RecalculateFoldersCountAsync(e);
}
foreach (var e in recalcFolders)
{
await GetRecalculateFilesCountUpdateAsync(e);
}
}
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
foreach (var e in recalcFolders)
{
await RecalculateFoldersCountAsync(e);
}
foreach (var e in recalcFolders)
{
await GetRecalculateFilesCountUpdateAsync(e);
}
}
});
return folderId;
}
@ -966,21 +995,27 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
folder.Title = key;
break;
}
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);//NOTE: Maybe we shouldn't start transaction here at all
newFolderId = await SaveFolderAsync(folder, tx).ConfigureAwait(false); //Save using our db manager
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
var newBunch = new DbFilesBunchObjects
await strategy.ExecuteAsync(async () =>
{
LeftNode = newFolderId.ToString(),
RightNode = key,
TenantId = TenantID
};
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);//NOTE: Maybe we shouldn't start transaction here at all
await FilesDbContext.AddOrUpdateAsync(r => r.BunchObjects, newBunch).ConfigureAwait(false);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
newFolderId = await SaveFolderAsync(folder, tx).ConfigureAwait(false); //Save using our db manager
await tx.CommitAsync().ConfigureAwait(false); //Commit changes
var newBunch = new DbFilesBunchObjects
{
LeftNode = newFolderId.ToString(),
RightNode = key,
TenantId = TenantID
};
await FilesDbContext.AddOrUpdateAsync(r => r.BunchObjects, newBunch).ConfigureAwait(false);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false); //Commit changes
});
}
folderIds.Add(newFolderId);
@ -1062,19 +1097,25 @@ internal class FolderDao : AbstractDao, IFolderDao<int>
folder.Title = key;
break;
}
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false); //NOTE: Maybe we shouldn't start transaction here at all
newFolderId = await SaveFolderAsync(folder, tx).ConfigureAwait(false); //Save using our db manager
var toInsert = new DbFilesBunchObjects
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
LeftNode = newFolderId.ToString(),
RightNode = key,
TenantId = TenantID
};
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false); //NOTE: Maybe we shouldn't start transaction here at all
newFolderId = await SaveFolderAsync(folder, tx).ConfigureAwait(false); //Save using our db manager
var toInsert = new DbFilesBunchObjects
{
LeftNode = newFolderId.ToString(),
RightNode = key,
TenantId = TenantID
};
await FilesDbContext.AddOrUpdateAsync(r => r.BunchObjects, toInsert).ConfigureAwait(false);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await FilesDbContext.AddOrUpdateAsync(r => r.BunchObjects, toInsert).ConfigureAwait(false);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false); //Commit changes
await tx.CommitAsync().ConfigureAwait(false); //Commit changes
});
}
return newFolderId;

View File

@ -64,23 +64,28 @@ internal class SecurityDao<T> : AbstractDao, ISecurityDao<T>
public async Task DeleteShareRecordsAsync(IEnumerable<FileShareRecord> records)
{
using var tx = await FilesDbContext.Database.BeginTransactionAsync();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
foreach (var record in records)
await strategy.ExecuteAsync(async () =>
{
var query = await FilesDbContext.Security
.AsQueryable()
.Where(r => r.TenantId == record.TenantId)
.Where(r => r.EntryType == record.EntryType)
.Where(r => r.Subject == record.Subject)
.AsAsyncEnumerable()
.WhereAwait(async r => r.EntryId == (await MappingIDAsync(record.EntryId)).ToString())
.ToListAsync();
using var tx = await FilesDbContext.Database.BeginTransactionAsync();
FilesDbContext.RemoveRange(query);
}
foreach (var record in records)
{
var query = await FilesDbContext.Security
.AsQueryable()
.Where(r => r.TenantId == record.TenantId)
.Where(r => r.EntryType == record.EntryType)
.Where(r => r.Subject == record.Subject)
.AsAsyncEnumerable()
.WhereAwait(async r => r.EntryId == (await MappingIDAsync(record.EntryId)).ToString())
.ToListAsync();
await tx.CommitAsync();
FilesDbContext.RemoveRange(query);
}
await tx.CommitAsync();
});
}
public ValueTask<bool> IsSharedAsync(object entryId, FileEntryType type)
@ -101,60 +106,66 @@ internal class SecurityDao<T> : AbstractDao, ISecurityDao<T>
return;
}
using var tx = await FilesDbContext.Database.BeginTransactionAsync();
var files = new List<string>();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
if (r.EntryType == FileEntryType.Folder)
{
var folders = new List<string>();
if (int.TryParse(entryId, out var intEntryId))
{
var foldersInt = await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.ParentId.ToString() == entryId)
.Select(r => r.FolderId)
.ToListAsync();
await strategy.ExecuteAsync(async () =>
{
using var tx = await FilesDbContext.Database.BeginTransactionAsync();
var files = new List<string>();
folders.AddRange(foldersInt.Select(folderInt => folderInt.ToString()));
files.AddRange(await Query(FilesDbContext.Files).Where(r => foldersInt.Contains(r.ParentId)).Select(r => r.Id.ToString()).ToListAsync());
}
else
{
folders.Add(entryId);
}
if (r.EntryType == FileEntryType.Folder)
{
var folders = new List<string>();
if (int.TryParse(entryId, out var intEntryId))
{
var foldersInt = await FilesDbContext.Tree
.AsQueryable()
.Where(r => r.ParentId.ToString() == entryId)
.Select(r => r.FolderId)
.ToListAsync();
var toDelete = await FilesDbContext.Security
.AsQueryable()
.Where(a => a.TenantId == r.TenantId &&
folders.Contains(a.EntryId) &&
a.EntryType == FileEntryType.Folder &&
a.Subject == r.Subject)
.ToListAsync();
folders.AddRange(foldersInt.Select(folderInt => folderInt.ToString()));
files.AddRange(await Query(FilesDbContext.Files).Where(r => foldersInt.Contains(r.ParentId)).Select(r => r.Id.ToString()).ToListAsync());
}
else
{
folders.Add(entryId);
}
FilesDbContext.Security.RemoveRange(toDelete);
await FilesDbContext.SaveChangesAsync();
var toDelete = await FilesDbContext.Security
.AsQueryable()
.Where(a => a.TenantId == r.TenantId &&
folders.Contains(a.EntryId) &&
a.EntryType == FileEntryType.Folder &&
a.Subject == r.Subject)
.ToListAsync();
}
else
{
files.Add(entryId);
}
FilesDbContext.Security.RemoveRange(toDelete);
await FilesDbContext.SaveChangesAsync();
if (0 < files.Count)
{
var toDelete = await FilesDbContext.Security
.AsQueryable()
.Where(a => a.TenantId == r.TenantId &&
files.Contains(a.EntryId) &&
a.EntryType == FileEntryType.File &&
a.Subject == r.Subject)
.ToListAsync();
}
else
{
files.Add(entryId);
}
FilesDbContext.Security.RemoveRange(toDelete);
await FilesDbContext.SaveChangesAsync();
}
if (0 < files.Count)
{
var toDelete = await FilesDbContext.Security
.AsQueryable()
.Where(a => a.TenantId == r.TenantId &&
files.Contains(a.EntryId) &&
a.EntryType == FileEntryType.File &&
a.Subject == r.Subject)
.ToListAsync();
await tx.CommitAsync();
FilesDbContext.Security.RemoveRange(toDelete);
await FilesDbContext.SaveChangesAsync();
}
await tx.CommitAsync();
});
}
else
{
@ -363,18 +374,23 @@ internal class SecurityDao<T> : AbstractDao, ISecurityDao<T>
public async Task RemoveSubjectAsync(Guid subject)
{
using var tr = await FilesDbContext.Database.BeginTransactionAsync();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
var toDelete1 = await FilesDbContext.Security.AsQueryable().Where(r => r.Subject == subject).ToListAsync();
var toDelete2 = await FilesDbContext.Security.AsQueryable().Where(r => r.Owner == subject).ToListAsync();
await strategy.ExecuteAsync(async () =>
{
using var tr = await FilesDbContext.Database.BeginTransactionAsync();
FilesDbContext.RemoveRange(toDelete1);
await FilesDbContext.SaveChangesAsync();
var toDelete1 = await FilesDbContext.Security.AsQueryable().Where(r => r.Subject == subject).ToListAsync();
var toDelete2 = await FilesDbContext.Security.AsQueryable().Where(r => r.Owner == subject).ToListAsync();
FilesDbContext.RemoveRange(toDelete2);
await FilesDbContext.SaveChangesAsync();
FilesDbContext.RemoveRange(toDelete1);
await FilesDbContext.SaveChangesAsync();
await tr.CommitAsync();
FilesDbContext.RemoveRange(toDelete2);
await FilesDbContext.SaveChangesAsync();
await tr.CommitAsync();
});
}
private IQueryable<DbFilesSecurity> GetQuery(Expression<Func<DbFilesSecurity, bool>> where = null)

View File

@ -233,15 +233,20 @@ internal class TagDao<T> : AbstractDao, ITagDao<T>
lock (_syncRoot)
{
using var tx = FilesDbContext.Database.BeginTransaction();
DeleteTagsBeforeSave();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
var cacheTagId = new Dictionary<string, int>();
strategy.Execute(() =>
{
using var tx = FilesDbContext.Database.BeginTransaction();
DeleteTagsBeforeSave();
result.AddRange(tags.Select(t => SaveTagAsync(t, cacheTagId, createOn).Result));
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
var cacheTagId = new Dictionary<string, int>();
tx.Commit();
result.AddRange(tags.Select(t => SaveTagAsync(t, cacheTagId, createOn).Result));
tx.Commit();
});
}
return result;
@ -263,15 +268,20 @@ internal class TagDao<T> : AbstractDao, ITagDao<T>
lock (_syncRoot)
{
using var tx = FilesDbContext.Database.BeginTransaction();
DeleteTagsBeforeSave();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
var cacheTagId = new Dictionary<string, int>();
strategy.Execute(() =>
{
using var tx = FilesDbContext.Database.BeginTransaction();
DeleteTagsBeforeSave();
result.Add(SaveTagAsync(tag, cacheTagId, createOn).Result);
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
var cacheTagId = new Dictionary<string, int>();
tx.Commit();
result.Add(SaveTagAsync(tag, cacheTagId, createOn).Result);
tx.Commit();
});
}
return result;
@ -368,15 +378,20 @@ internal class TagDao<T> : AbstractDao, ITagDao<T>
lock (_syncRoot)
{
using var tx = FilesDbContext.Database.BeginTransaction();
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
foreach (var tag in tags)
strategy.Execute(() =>
{
UpdateNewTagsInDbAsync(tag, createOn).Wait();
}
using var tx = FilesDbContext.Database.BeginTransaction();
var createOn = _tenantUtil.DateTimeToUtc(_tenantUtil.DateTimeNow());
tx.Commit();
foreach (var tag in tags)
{
UpdateNewTagsInDbAsync(tag, createOn).Wait();
}
tx.Commit();
});
}
}
@ -432,13 +447,19 @@ internal class TagDao<T> : AbstractDao, ITagDao<T>
lock (_syncRoot)
{
using var tx = FilesDbContext.Database.BeginTransaction();
foreach (var t in tags)
{
RemoveTagInDbAsync(t).Wait();
}
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
tx.Commit();
strategy.Execute(() =>
{
using var tx = FilesDbContext.Database.BeginTransaction();
foreach (var t in tags)
{
RemoveTagInDbAsync(t).Wait();
}
tx.Commit();
});
}
}
@ -451,10 +472,16 @@ internal class TagDao<T> : AbstractDao, ITagDao<T>
lock (_syncRoot)
{
using var tx = FilesDbContext.Database.BeginTransaction();
RemoveTagInDbAsync(tag).Wait();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
tx.Commit();
strategy.Execute(() =>
{
using var tx = FilesDbContext.Database.BeginTransaction();
RemoveTagInDbAsync(tag).Wait();
tx.Commit();
});
}
}

View File

@ -349,40 +349,45 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
var id = MakeId(boxFile.Id);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync();
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync();
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
await tx.CommitAsync().ConfigureAwait(false);
}
});
if (boxFile is not ErrorFile)
{

View File

@ -225,43 +225,48 @@ internal class BoxFolderDao : BoxDaoBase, IFolderDao<string>
var boxFolder = await GetBoxFolderAsync(folderId).ConfigureAwait(false);
var id = MakeId(boxFolder);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
await tx.CommitAsync().ConfigureAwait(false);
}
});
if (boxFolder is not ErrorFolder)
{

View File

@ -349,43 +349,49 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
var id = MakeId(dropboxFile);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync())
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync())
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
});
await tx.CommitAsync().ConfigureAwait(false);
}
if (dropboxFile is not ErrorFile)
{

View File

@ -224,43 +224,48 @@ internal class DropboxFolderDao : DropboxDaoBase, IFolderDao<string>
var dropboxFolder = await GetDropboxFolderAsync(folderId).ConfigureAwait(false);
var id = MakeId(dropboxFolder);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
await tx.CommitAsync().ConfigureAwait(false);
}
});
if (dropboxFolder is not ErrorFolder)
{

View File

@ -344,43 +344,48 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
var id = MakeId(driveFile.Id);
using (var tx = FilesDbContext.Database.BeginTransaction())
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync())
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
await tx.CommitAsync().ConfigureAwait(false);
}
});
if (driveFile is not ErrorDriveEntry)
{

View File

@ -214,43 +214,49 @@ internal class GoogleDriveFolderDao : GoogleDriveDaoBase, IFolderDao<string>
var driveFolder = await GetDriveEntryAsync(folderId).ConfigureAwait(false);
var id = MakeId(driveFolder);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
});
await tx.CommitAsync().ConfigureAwait(false);
}
if (driveFolder is not ErrorDriveEntry)
{

View File

@ -352,43 +352,48 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao<string>
var id = MakeId(onedriveFile.Id);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
await tx.CommitAsync().ConfigureAwait(false);
}
});
if (onedriveFile is not ErrorItem)
{

View File

@ -222,42 +222,49 @@ internal class OneDriveFolderDao : OneDriveDaoBase, IFolderDao<string>
var onedriveFolder = await GetOneDriveItemAsync(folderId).ConfigureAwait(false);
var id = MakeId(onedriveFolder);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync().ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
});
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
if (onedriveFolder is not ErrorItem)
{

View File

@ -310,48 +310,53 @@ internal class ProviderAccountDao : IProviderDao
public virtual async Task RemoveProviderInfoAsync(int linkId)
{
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);
var folderId = (await GetProviderInfoAsync(linkId)).RootFolderId;
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
var entryIDs = await FilesDbContext.ThirdpartyIdMapping
.AsQueryable()
.Where(r => r.TenantId == TenantID)
.Where(r => r.Id.StartsWith(folderId))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
await strategy.ExecuteAsync(async () =>
{
using var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false);
var folderId = (await GetProviderInfoAsync(linkId)).RootFolderId;
var forDelete = await FilesDbContext.Security
.AsQueryable()
.Where(r => r.TenantId == TenantID)
.Where(r => entryIDs.Any(a => a == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var entryIDs = await FilesDbContext.ThirdpartyIdMapping
.AsQueryable()
.Where(r => r.TenantId == TenantID)
.Where(r => r.Id.StartsWith(folderId))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(forDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var forDelete = await FilesDbContext.Security
.AsQueryable()
.Where(r => r.TenantId == TenantID)
.Where(r => entryIDs.Any(a => a == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var linksForDelete = await FilesDbContext.TagLink
.AsQueryable()
.Where(r => r.TenantId == TenantID)
.Where(r => entryIDs.Any(e => e == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(forDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(linksForDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var linksForDelete = await FilesDbContext.TagLink
.AsQueryable()
.Where(r => r.TenantId == TenantID)
.Where(r => entryIDs.Any(e => e == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var accountsForDelete = await FilesDbContext.ThirdpartyAccount
.AsQueryable()
.Where(r => r.Id == linkId)
.Where(r => r.TenantId == TenantID)
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(linksForDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyAccount.RemoveRange(accountsForDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var accountsForDelete = await FilesDbContext.ThirdpartyAccount
.AsQueryable()
.Where(r => r.Id == linkId)
.Where(r => r.TenantId == TenantID)
.ToListAsync()
.ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyAccount.RemoveRange(accountsForDelete);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
});
}
private IProviderInfo ToProviderInfo(int id, ProviderTypes providerKey, string customerTitle, AuthData authData, Guid owner, FolderType type, DateTime createOn)

View File

@ -124,54 +124,59 @@ internal class SharePointDaoBase : ThirdPartyProviderDao<SharePointProviderInfo>
private async Task InternalUpdatePathInDBAsync(string oldValue, string newValue)
{
using var tx = FilesDbContext.Database.BeginTransaction();
var oldIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(oldValue))
.Select(r => r.Id)
.ToListAsync();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
foreach (var oldID in oldIDs)
await strategy.ExecuteAsync(async () =>
{
var oldHashID = await MappingIDAsync(oldID);
var newID = oldID.Replace(oldValue, newValue);
var newHashID = await MappingIDAsync(newID);
var mappingForUpdate = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.HashId == oldHashID)
using var tx = FilesDbContext.Database.BeginTransaction();
var oldIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(oldValue))
.Select(r => r.Id)
.ToListAsync();
foreach (var m in mappingForUpdate)
foreach (var oldID in oldIDs)
{
m.Id = newID;
m.HashId = newHashID;
var oldHashID = await MappingIDAsync(oldID);
var newID = oldID.Replace(oldValue, newValue);
var newHashID = await MappingIDAsync(newID);
var mappingForUpdate = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.HashId == oldHashID)
.ToListAsync();
foreach (var m in mappingForUpdate)
{
m.Id = newID;
m.HashId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
var securityForUpdate = await Query(FilesDbContext.Security)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var s in securityForUpdate)
{
s.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
var linkForUpdate = await Query(FilesDbContext.TagLink)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var l in linkForUpdate)
{
l.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
}
await FilesDbContext.SaveChangesAsync();
var securityForUpdate = await Query(FilesDbContext.Security)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var s in securityForUpdate)
{
s.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
var linkForUpdate = await Query(FilesDbContext.TagLink)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var l in linkForUpdate)
{
l.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
}
await tx.CommitAsync();
await tx.CommitAsync();
});
}
protected Task<string> MappingIDAsync(string id)

View File

@ -210,43 +210,49 @@ internal class SharePointFolderDao : SharePointDaoBase, IFolderDao<string>
{
var folder = await ProviderInfo.GetFolderByIdAsync(folderId).ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(folder.ServerRelativeUrl))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(folder.ServerRelativeUrl))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
});
await tx.CommitAsync().ConfigureAwait(false);
}
await ProviderInfo.DeleteFolderAsync(folderId).ConfigureAwait(false);
}

View File

@ -144,54 +144,59 @@ internal abstract class SharpBoxDaoBase : ThirdPartyProviderDao<SharpBoxProvider
return;
}
using var tx = FilesDbContext.Database.BeginTransaction();
var oldIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(oldValue))
.Select(r => r.Id)
.ToListAsync();
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
foreach (var oldID in oldIDs)
await strategy.ExecuteAsync(async () =>
{
var oldHashID = await MappingIDAsync(oldID);
var newID = oldID.Replace(oldValue, newValue);
var newHashID = await MappingIDAsync(newID);
var mappingForUpdate = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.HashId == oldHashID)
using var tx = await FilesDbContext.Database.BeginTransactionAsync();
var oldIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(oldValue))
.Select(r => r.Id)
.ToListAsync();
foreach (var m in mappingForUpdate)
foreach (var oldID in oldIDs)
{
m.Id = newID;
m.HashId = newHashID;
var oldHashID = await MappingIDAsync(oldID);
var newID = oldID.Replace(oldValue, newValue);
var newHashID = await MappingIDAsync(newID);
var mappingForUpdate = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.HashId == oldHashID)
.ToListAsync();
foreach (var m in mappingForUpdate)
{
m.Id = newID;
m.HashId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
var securityForUpdate = await Query(FilesDbContext.Security)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var s in securityForUpdate)
{
s.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
var linkForUpdate = await Query(FilesDbContext.TagLink)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var l in linkForUpdate)
{
l.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
}
await FilesDbContext.SaveChangesAsync();
var securityForUpdate = await Query(FilesDbContext.Security)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var s in securityForUpdate)
{
s.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
var linkForUpdate = await Query(FilesDbContext.TagLink)
.Where(r => r.EntryId == oldHashID)
.ToListAsync();
foreach (var l in linkForUpdate)
{
l.EntryId = newHashID;
}
await FilesDbContext.SaveChangesAsync();
}
await tx.CommitAsync();
await tx.CommitAsync();
});
}
protected string MakePath(object entryId)

View File

@ -363,43 +363,51 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao<string>
var id = MakeId(file);
using (var tx = FilesDbContext.Database.BeginTransaction())
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = FilesDbContext.Database.BeginTransaction())
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
});
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
if (file is not ErrorEntry)
{

View File

@ -220,43 +220,51 @@ internal class SharpBoxFolderDao : SharpBoxDaoBase, IFolderDao<string>
var folder = GetFolderById(folderId);
var id = MakeId(folder);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
var strategy = FilesDbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
using (var tx = await FilesDbContext.Database.BeginTransactionAsync().ConfigureAwait(false))
{
var hashIDs = await Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => r.Id.StartsWith(id))
.Select(r => r.HashId)
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
var link = await Query(FilesDbContext.TagLink)
.Where(r => hashIDs.Any(h => h == r.EntryId))
.ToListAsync()
.ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.TagLink.RemoveRange(link);
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
var tagsToRemove = from ft in FilesDbContext.Tag
join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId }
where ftl == null
select ft;
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
FilesDbContext.Tag.RemoveRange(await tagsToRemove.ToListAsync());
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
var securityToDelete = Query(FilesDbContext.Security)
.Where(r => hashIDs.Any(h => h == r.EntryId));
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
FilesDbContext.Security.RemoveRange(await securityToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
});
var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping)
.Where(r => hashIDs.Any(h => h == r.HashId));
FilesDbContext.ThirdpartyIdMapping.RemoveRange(await mappingToDelete.ToListAsync());
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
await tx.CommitAsync().ConfigureAwait(false);
}
if (folder is not ErrorEntry)
{

View File

@ -26,16 +26,32 @@
namespace ASC.Web.Files.Services.WCFService.FileOperations;
[ProtoContract]
[ProtoInclude(100, typeof(FileConverterOperationResult))]
public class FileOperationResult
{
[ProtoMember(1)]
public string Id { get; set; }
[JsonPropertyName("operation")]
[ProtoMember(2)]
public FileOperationType OperationType { get; set; }
[ProtoMember(3)]
public int Progress { get; set; }
[ProtoMember(4)]
public string Source { get; set; }
[ProtoMember(5)]
public string Result { get; set; }
[ProtoMember(6)]
public string Error { get; set; }
[ProtoMember(7)]
public string Processed { get; set; }
[ProtoMember(8)]
public bool Finished { get; set; }
}

View File

@ -24,44 +24,42 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using Microsoft.Extensions.Caching.Distributed;
using Timeout = System.Threading.Timeout;
namespace ASC.Web.Files.Utils;
[Singletone(Additional = typeof(FileConverterQueueExtension))]
internal class FileConverterQueue<T> : IDisposable
[Singletone]
public class FileConverterQueue<T>
{
private readonly object _singleThread = new object();
private readonly IDictionary<File<T>, ConvertFileOperationResult> _conversionQueue;
private readonly Timer _timer;
private readonly object _locker;
private readonly ICache _cache;
private const int _timerPeriod = 500;
private readonly object _locker = new object();
private readonly IDistributedCache _distributedCache;
private readonly string _cache_key_prefix = "asc_file_converter_queue_";
private readonly IServiceScopeFactory _serviceScopeFactory;
public FileConverterQueue(IServiceScopeFactory serviceScopeFactory, ICache cache)
public FileConverterQueue(IDistributedCache distributedCache)
{
_conversionQueue = new Dictionary<File<T>, ConvertFileOperationResult>(new FileComparer<T>());
_timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite);
_locker = new object();
_serviceScopeFactory = serviceScopeFactory;
_cache = cache;
_distributedCache = distributedCache;
}
public void Add(File<T> file, string password, int tenantId, IAccount account, bool deleteAfter, string url, string serverRootPath)
public void Add(File<T> file,
string password,
int tenantId,
IAccount account,
bool deleteAfter,
string url,
string serverRootPath)
{
lock (_locker)
{
if (_conversionQueue.ContainsKey(file))
var task = PeekTask(file);
if (Contains(task))
{
return;
}
var queueResult = new ConvertFileOperationResult
var queueResult = new FileConverterOperationResult
{
Source = string.Format("{{\"id\":\"{0}\", \"version\":\"{1}\"}}", file.Id, file.Version),
Source = System.Text.Json.JsonSerializer.Serialize(new { id = file.Id, version = file.Version }),
OperationType = FileOperationType.Convert,
Error = string.Empty,
Progress = 0,
@ -69,316 +67,95 @@ internal class FileConverterQueue<T> : IDisposable
Processed = "",
Id = string.Empty,
TenantId = tenantId,
Account = account,
Account = account.ID,
Delete = deleteAfter,
StartDateTime = DateTime.Now,
Url = url,
Password = password,
ServerRootPath = serverRootPath
};
_conversionQueue.Add(file, queueResult);
_cache.Insert(GetKey(file), queueResult, TimeSpan.FromMinutes(10));
_timer.Change(0, Timeout.Infinite);
Enqueue(queueResult);
}
}
public async Task<ConvertFileOperationResult> GetStatusAsync(KeyValuePair<File<T>, bool> pair, FileSecurity fileSecurity)
public void Enqueue(FileConverterOperationResult val)
{
var file = pair.Key;
var key = GetKey(file);
var operation = _cache.Get<ConvertFileOperationResult>(key);
if (operation != null && (pair.Value || await fileSecurity.CanReadAsync(file)))
var fromCache = LoadFromCache().ToList();
fromCache.Add(val);
SaveToCache(fromCache);
}
public void Dequeue(FileConverterOperationResult val)
{
var fromCache = LoadFromCache().ToList();
fromCache.Remove(val);
SaveToCache(fromCache);
}
public FileConverterOperationResult PeekTask(File<T> file)
{
var exist = LoadFromCache();
return exist.FirstOrDefault(x =>
{
lock (_locker)
{
if (operation.Progress == 100)
{
_conversionQueue.Remove(file);
_cache.Remove(key);
}
var fileId = JsonDocument.Parse(x.Source).RootElement.GetProperty("id").Deserialize<T>();
var fileVersion = JsonDocument.Parse(x.Source).RootElement.GetProperty("version").Deserialize<int>();
return operation;
}
}
return null;
return file.Id.ToString() == fileId.ToString() && file.Version == fileVersion;
});
}
public bool IsConverting(File<T> file)
{
var result = _cache.Get<ConvertFileOperationResult>(GetKey(file));
var result = PeekTask(file);
return result != null && result.Progress != 100 && string.IsNullOrEmpty(result.Error);
}
private void CheckConvertFilesStatus(object _)
public IEnumerable<FileConverterOperationResult> GetAllTask()
{
if (Monitor.TryEnter(_singleThread))
var queueTasks = LoadFromCache();
queueTasks = DeleteOrphanCacheItem(queueTasks);
return queueTasks;
}
public void SetAllTask(IEnumerable<FileConverterOperationResult> queueTasks)
{
SaveToCache(queueTasks);
}
public async Task<FileConverterOperationResult> GetStatusAsync(KeyValuePair<File<T>, bool> pair, FileSecurity fileSecurity)
{
var file = pair.Key;
var operation = PeekTask(pair.Key);
if (operation != null && (pair.Value || await fileSecurity.CanReadAsync(file)))
{
using var scope = _serviceScopeFactory.CreateScope();
TenantManager tenantManager;
UserManager userManager;
SecurityContext securityContext;
IDaoFactory daoFactory;
FileSecurity fileSecurity;
PathProvider pathProvider;
SetupInfo setupInfo;
FileUtility fileUtility;
DocumentServiceHelper documentServiceHelper;
DocumentServiceConnector documentServiceConnector;
EntryStatusManager entryManager;
FileConverter fileConverter;
var logger = scope.ServiceProvider.GetService<ILogger<FileConverterQueue<T>>>();
try
if (operation.Progress == 100)
{
var filesIsConverting = new List<File<T>>();
lock (_locker)
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
var queues = _conversionQueue.Where(x => !string.IsNullOrEmpty(x.Value.Processed)
&& (x.Value.Progress == 100 && DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(1) ||
DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(10)))
.ToList();
var task = PeekTask(file);
foreach (var q in queues)
{
_conversionQueue.Remove(q);
_cache.Remove(GetKey(q.Key));
}
logger.DebugRunCheckConvertFilesStatus(_conversionQueue.Count);
if (_conversionQueue.Count == 0)
{
return;
}
filesIsConverting = _conversionQueue
.Where(x => string.IsNullOrEmpty(x.Value.Processed))
.Select(x => x.Key)
.ToList();
}
string convertedFileUrl = null;
foreach (var file in filesIsConverting)
{
var fileUri = file.Id.ToString();
int operationResultProgress;
try
{
int tenantId;
IAccount account;
string password;
string serverRootPath;
lock (_locker)
{
if (!_conversionQueue.ContainsKey(file))
{
continue;
}
var operationResult = _conversionQueue[file];
if (!string.IsNullOrEmpty(operationResult.Processed))
{
continue;
}
operationResult.Processed = "1";
tenantId = operationResult.TenantId;
account = operationResult.Account;
password = operationResult.Password;
serverRootPath = operationResult.ServerRootPath;
//if (HttpContext.Current == null && !WorkContext.IsMono)
//{
// HttpContext.Current = new HttpContext(
// new HttpRequest("hack", operationResult.Url, string.Empty),
// new HttpResponse(new StringWriter()));
//}
_cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
}
var commonLinkUtilitySettings = scope.ServiceProvider.GetService<CommonLinkUtilitySettings>();
commonLinkUtilitySettings.ServerUri = serverRootPath;
var scopeClass = scope.ServiceProvider.GetService<FileConverterQueueScope>();
(_, tenantManager, userManager, securityContext, daoFactory, fileSecurity, pathProvider, setupInfo, fileUtility, documentServiceHelper, documentServiceConnector, entryManager, fileConverter) = scopeClass;
tenantManager.SetCurrentTenant(tenantId);
securityContext.AuthenticateMeWithoutCookie(account);
var user = userManager.GetUsers(account.ID);
var culture = string.IsNullOrEmpty(user.CultureName) ? tenantManager.GetCurrentTenant().GetCulture() : CultureInfo.GetCultureInfo(user.CultureName);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
if (!fileSecurity.CanReadAsync(file).Result && file.RootFolderType != FolderType.BUNCH)
{
//No rights in CRM after upload before attach
throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
}
if (file.ContentLength > setupInfo.AvailableFileSize)
{
throw new Exception(string.Format(FilesCommonResource.ErrorMassage_FileSizeConvert, FileSizeComment.FilesSizeToString(setupInfo.AvailableFileSize)));
}
fileUri = pathProvider.GetFileStreamUrl(file);
var toExtension = fileUtility.GetInternalExtension(file.Title);
var fileExtension = file.ConvertedExtension;
var docKey = documentServiceHelper.GetDocKey(file);
fileUri = documentServiceConnector.ReplaceCommunityAdress(fileUri);
(operationResultProgress, convertedFileUrl) = documentServiceConnector.GetConvertedUriAsync(fileUri, fileExtension, toExtension, docKey, password, null, null, true).Result;
}
catch (Exception exception)
{
var password = exception.InnerException is DocumentServiceException documentServiceException
&& documentServiceException.Code == DocumentServiceException.ErrorCode.ConvertPassword;
logger.ErrorConvertFileWithUrl(file.Id.ToString(), fileUri, exception);
lock (_locker)
{
if (_conversionQueue.TryGetValue(file, out var operationResult))
{
if (operationResult.Delete)
{
_conversionQueue.Remove(file);
_cache.Remove(GetKey(file));
}
else
{
operationResult.Progress = 100;
operationResult.StopDateTime = DateTime.UtcNow;
operationResult.Error = exception.Message;
if (password)
{
operationResult.Result = "password";
}
_cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
}
}
}
continue;
}
operationResultProgress = Math.Min(operationResultProgress, 100);
if (operationResultProgress < 100)
{
lock (_locker)
{
if (_conversionQueue.TryGetValue(file, out var operationResult))
{
if (DateTime.Now - operationResult.StartDateTime > TimeSpan.FromMinutes(10))
{
operationResult.StopDateTime = DateTime.UtcNow;
operationResult.Error = FilesCommonResource.ErrorMassage_ConvertTimeout;
logger.ErrorCheckConvertFilesStatus(file.Id.ToString(), file.ContentLength);
}
else
{
operationResult.Processed = "";
}
operationResult.Progress = operationResultProgress;
_cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
}
}
logger.DebugCheckConvertFilesStatusIterationContinue();
continue;
}
File<T> newFile = null;
var operationResultError = string.Empty;
try
{
newFile = fileConverter.SaveConvertedFileAsync(file, convertedFileUrl).Result;
}
catch (Exception e)
{
operationResultError = e.Message;
logger.ErrorOperation(operationResultError, convertedFileUrl, fileUri, e);
continue;
}
finally
{
lock (_locker)
{
if (_conversionQueue.TryGetValue(file, out var operationResult))
{
if (operationResult.Delete)
{
_conversionQueue.Remove(file);
_cache.Remove(GetKey(file));
}
else
{
if (newFile != null)
{
var folderDao = daoFactory.GetFolderDao<T>();
var folder = folderDao.GetFolderAsync(newFile.ParentId).Result;
var folderTitle = fileSecurity.CanReadAsync(folder).Result ? folder.Title : null;
operationResult.Result = FileJsonSerializerAsync(entryManager, newFile, folderTitle).Result;
}
operationResult.Progress = 100;
operationResult.StopDateTime = DateTime.UtcNow;
operationResult.Processed = "1";
if (!string.IsNullOrEmpty(operationResultError))
{
operationResult.Error = operationResultError;
}
_cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
}
}
}
}
logger.DebugCheckConvertFilesStatusIterationEnd();
}
lock (_locker)
{
_timer.Change(_timerPeriod, _timerPeriod);
}
}
catch (Exception exception)
{
logger.ErrorWithException(exception);
lock (_locker)
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
finally
{
Monitor.Exit(_singleThread);
Dequeue(task);
}
return operation;
}
return null;
}
private string GetKey(File<T> f)
{
return string.Format("fileConvertation-{0}", f.Id);
}
internal async Task<string> FileJsonSerializerAsync(EntryStatusManager EntryManager, File<T> file, string folderTitle)
public async Task<string> FileJsonSerializerAsync(EntryStatusManager EntryManager, File<T> file, string folderTitle)
{
if (file == null)
{
@ -406,94 +183,73 @@ internal class FileConverterQueue<T> : IDisposable
}, options);
}
public void Dispose()
private bool Contains(FileConverterOperationResult val)
{
if (_timer != null)
var queueTasks = LoadFromCache();
return queueTasks.Any(x =>
{
_timer.Dispose();
return String.Compare(x.Source, val.Source) == 0;
});
}
private bool IsOrphanCacheItem(FileConverterOperationResult x)
{
return !string.IsNullOrEmpty(x.Processed)
&& (x.Progress == 100 && DateTime.UtcNow - x.StopDateTime > TimeSpan.FromMinutes(1) ||
DateTime.UtcNow - x.StopDateTime > TimeSpan.FromMinutes(10));
}
private IEnumerable<FileConverterOperationResult> DeleteOrphanCacheItem(IEnumerable<FileConverterOperationResult> queueTasks)
{
var listTasks = queueTasks.ToList();
listTasks.RemoveAll(IsOrphanCacheItem);
SaveToCache(listTasks);
return queueTasks;
}
private void SaveToCache(IEnumerable<FileConverterOperationResult> queueTasks)
{
if (!queueTasks.Any())
{
_distributedCache.Remove(GetCacheKey());
return;
}
using var ms = new MemoryStream();
ProtoBuf.Serializer.Serialize(ms, queueTasks);
_distributedCache.Set(GetCacheKey(), ms.ToArray(), new DistributedCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(15)
});
}
private string GetCacheKey()
{
return $"{_cache_key_prefix}_{typeof(T).Name}".ToLowerInvariant();
}
private IEnumerable<FileConverterOperationResult> LoadFromCache()
{
var serializedObject = _distributedCache.Get(GetCacheKey());
if (serializedObject == null)
{
return new List<FileConverterOperationResult>();
}
using var ms = new MemoryStream(serializedObject);
return ProtoBuf.Serializer.Deserialize<List<FileConverterOperationResult>>(ms);
}
}
[Scope]
public class FileConverterQueueScope
{
private readonly ILogger _options;
private readonly TenantManager _tenantManager;
private readonly UserManager _userManager;
private readonly SecurityContext _securityContext;
private readonly IDaoFactory _daoFactory;
private readonly FileSecurity _fileSecurity;
private readonly PathProvider _pathProvider;
private readonly SetupInfo _setupInfo;
private readonly FileUtility _fileUtility;
private readonly DocumentServiceHelper _documentServiceHelper;
private readonly DocumentServiceConnector _documentServiceConnector;
private readonly EntryStatusManager _entryManager;
private readonly FileConverter _fileConverter;
public FileConverterQueueScope(
ILogger<FileConverterQueueScope> options,
TenantManager tenantManager,
UserManager userManager,
SecurityContext securityContext,
IDaoFactory daoFactory,
FileSecurity fileSecurity,
PathProvider pathProvider,
SetupInfo setupInfo,
FileUtility fileUtility,
DocumentServiceHelper documentServiceHelper,
DocumentServiceConnector documentServiceConnector,
EntryStatusManager entryManager,
FileConverter fileConverter)
{
_options = options;
_tenantManager = tenantManager;
_userManager = userManager;
_securityContext = securityContext;
_daoFactory = daoFactory;
_fileSecurity = fileSecurity;
_pathProvider = pathProvider;
_setupInfo = setupInfo;
_fileUtility = fileUtility;
_documentServiceHelper = documentServiceHelper;
_documentServiceConnector = documentServiceConnector;
_entryManager = entryManager;
_fileConverter = fileConverter;
}
public void Deconstruct(out ILogger optionsMonitor,
out TenantManager tenantManager,
out UserManager userManager,
out SecurityContext securityContext,
out IDaoFactory daoFactory,
out FileSecurity fileSecurity,
out PathProvider pathProvider,
out SetupInfo setupInfo,
out FileUtility fileUtility,
out DocumentServiceHelper documentServiceHelper,
out DocumentServiceConnector documentServiceConnector,
out EntryStatusManager entryManager,
out FileConverter fileConverter)
{
optionsMonitor = _options;
tenantManager = _tenantManager;
userManager = _userManager;
securityContext = _securityContext;
daoFactory = _daoFactory;
fileSecurity = _fileSecurity;
pathProvider = _pathProvider;
setupInfo = _setupInfo;
fileUtility = _fileUtility;
documentServiceHelper = _documentServiceHelper;
documentServiceConnector = _documentServiceConnector;
entryManager = _entryManager;
fileConverter = _fileConverter;
}
}
public class FileJsonSerializerData<T>
{
public T Id { get; set; }
@ -710,9 +466,9 @@ public class FileConverter
var uriTuple = await _documentServiceConnector.GetConvertedUriAsync(fileUri, fileExtension, toExtension, docKey, null, null, null, false);
var convertUri = uriTuple.ConvertedDocumentUri;
var operationResult = new ConvertFileOperationResult
var operationResult = new FileConverterOperationResult
{
Source = string.Format("{{\"id\":\"{0}\", \"version\":\"{1}\"}}", file.Id, file.Version),
Source = System.Text.Json.JsonSerializer.Serialize(new { id = file.Id, version = file.Version }),
OperationType = FileOperationType.Convert,
Error = string.Empty,
Progress = 0,
@ -720,7 +476,7 @@ public class FileConverter
Processed = "",
Id = string.Empty,
TenantId = _tenantManager.GetCurrentTenant().Id,
Account = _authContext.CurrentAccount,
Account = _authContext.CurrentAccount.ID,
Delete = false,
StartDateTime = DateTime.Now,
Url = _httpContextAccesor?.HttpContext != null ? _httpContextAccesor.HttpContext.Request.GetUrlRewriter().ToString() : null,
@ -918,27 +674,6 @@ internal class FileComparer<T> : IEqualityComparer<File<T>>
}
}
internal class ConvertFileOperationResult : FileOperationResult
{
public DateTime StartDateTime { get; set; }
public DateTime StopDateTime { get; set; }
public int TenantId { get; set; }
public IAccount Account { get; set; }
public bool Delete { get; set; }
public string Url { get; set; }
public string Password { get; set; }
//hack for download
public string ServerRootPath { get; set; }
}
public static class FileConverterQueueExtension
{
public static void Register(DIHelper services)
{
services.TryAdd<FileConverterQueueScope>();
}
}
public static class FileConverterExtension
{

View File

@ -0,0 +1,56 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Web.Files.Utils;
[ProtoContract]
public class FileConverterOperationResult : FileOperationResult
{
[ProtoMember(1)]
public DateTime StartDateTime { get; set; }
[ProtoMember(2)]
public DateTime StopDateTime { get; set; }
[ProtoMember(3)]
public int TenantId { get; set; }
[ProtoMember(4)]
public Guid Account { get; set; }
[ProtoMember(5)]
public bool Delete { get; set; }
[ProtoMember(6)]
public string Url { get; set; }
[ProtoMember(7)]
public string Password { get; set; }
[ProtoMember(8)]
//hack for download
public string ServerRootPath { get; set; }
}

View File

@ -27,14 +27,14 @@
namespace ASC.Api.Documents;
[ConstraintRoute("int")]
internal class PrivacyRoomControllerInternal : PrivacyRoomController<int>
public class PrivacyRoomControllerInternal : PrivacyRoomController<int>
{
public PrivacyRoomControllerInternal(SettingsManager settingsManager, EncryptionKeyPairDtoHelper encryptionKeyPairHelper, FileStorageService<int> fileStorageService) : base(settingsManager, encryptionKeyPairHelper, fileStorageService)
{
}
}
internal class PrivacyRoomControllerThirdparty : PrivacyRoomController<string>
public class PrivacyRoomControllerThirdparty : PrivacyRoomController<string>
{
public PrivacyRoomControllerThirdparty(SettingsManager settingsManager, EncryptionKeyPairDtoHelper encryptionKeyPairHelper, FileStorageService<string> fileStorageService) : base(settingsManager, encryptionKeyPairHelper, fileStorageService)
{
@ -45,7 +45,7 @@ internal class PrivacyRoomControllerThirdparty : PrivacyRoomController<string>
[DefaultRoute]
[ApiController]
[ControllerName("privacyroom")]
internal abstract class PrivacyRoomController<T> : ControllerBase
public abstract class PrivacyRoomController<T> : ControllerBase
{
private readonly EncryptionKeyPairDtoHelper _encryptionKeyPairHelper;
private readonly FileStorageService<T> _fileStorageService;
@ -81,7 +81,7 @@ internal abstract class PrivacyRoomController<T> : ControllerBase
[DefaultRoute]
[ApiController]
[ControllerName("privacyroom")]
public abstract class PrivacyRoomControllerCommon : ControllerBase
public class PrivacyRoomControllerCommon : ControllerBase
{
private readonly AuthContext _authContext;
private readonly EncryptionKeyPairDtoHelper _encryptionKeyPairHelper;

View File

@ -0,0 +1,362 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using System.Globalization;
using System.Text.Json;
using ASC.Common.Log;
using ASC.Core.Common.Hosting;
using ASC.Core.Common.Hosting.Interfaces;
using ASC.Files.Core.Log;
using ASC.Files.Core.Resources;
using ASC.Web.Files.Utils;
using ASC.Web.Studio.Core;
using static ASC.Web.Core.Files.DocumentService;
namespace ASC.Files.ThumbnailBuilder;
[Singletone(Additional = typeof(FileConverterQueueExtension))]
internal class FileConverterService<T> : BackgroundService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly int _timerDelay = 1000;
private readonly ILogger<FileConverterService<T>> _logger;
public FileConverterService(
IServiceScopeFactory serviceScopeFactory,
ILogger<FileConverterService<T>> logger)
{
_logger = logger;
_serviceScopeFactory = serviceScopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.DebugFileConverterServiceRuning();
stoppingToken.Register(() => _logger.DebugFileConverterServiceStopping());
while (!stoppingToken.IsCancellationRequested)
{
using var serviceScope = _serviceScopeFactory.CreateScope();
var registerInstanceService = serviceScope.ServiceProvider.GetService<IRegisterInstanceManager<FileConverterService<T>>>();
if (!await registerInstanceService.IsActive(RegisterInstanceWorkerService<FileConverterService<T>>.InstanceId))
{
await Task.Delay(1000, stoppingToken);
continue;
}
await ExecuteCheckFileConverterStatus(serviceScope);
await Task.Delay(_timerDelay, stoppingToken);
}
}
private async Task ExecuteCheckFileConverterStatus(IServiceScope scope)
{
TenantManager tenantManager;
UserManager userManager;
SecurityContext securityContext;
IDaoFactory daoFactory;
FileSecurity fileSecurity;
PathProvider pathProvider;
SetupInfo setupInfo;
FileUtility fileUtility;
DocumentServiceHelper documentServiceHelper;
DocumentServiceConnector documentServiceConnector;
EntryStatusManager entryManager;
FileConverter fileConverter;
FileConverterQueue<T> fileConverterQueue;
var logger = scope.ServiceProvider.GetService<ILogger<FileConverterQueue<T>>>();
try
{
var scopeClass = scope.ServiceProvider.GetService<FileConverterQueueScope>();
(_, tenantManager, userManager, securityContext, daoFactory, fileSecurity, pathProvider, setupInfo, fileUtility, documentServiceHelper, documentServiceConnector, entryManager, fileConverter) = scopeClass;
fileConverterQueue = scope.ServiceProvider.GetService<FileConverterQueue<T>>();
var _conversionQueue = fileConverterQueue.GetAllTask().ToList();
logger.DebugRunCheckConvertFilesStatus(_conversionQueue.Count);
var filesIsConverting = _conversionQueue
.Where(x => string.IsNullOrEmpty(x.Processed))
.ToList();
foreach (var converter in filesIsConverting)
{
var fileId = JsonDocument.Parse(converter.Source).RootElement.GetProperty("id").Deserialize<T>();
var fileVersion = JsonDocument.Parse(converter.Source).RootElement.GetProperty("version").Deserialize<int>();
int operationResultProgress;
var password = converter.Password;
var commonLinkUtilitySettings = scope.ServiceProvider.GetService<CommonLinkUtilitySettings>();
commonLinkUtilitySettings.ServerUri = converter.ServerRootPath;
tenantManager.SetCurrentTenant(converter.TenantId);
securityContext.AuthenticateMeWithoutCookie(converter.Account);
var file = await daoFactory.GetFileDao<T>().GetFileAsync(fileId, fileVersion);
var fileUri = file.Id.ToString();
string convertedFileUrl;
try
{
var user = userManager.GetUsers(converter.Account);
var culture = string.IsNullOrEmpty(user.CultureName) ? tenantManager.GetCurrentTenant().GetCulture() : CultureInfo.GetCultureInfo(user.CultureName);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
if (!fileSecurity.CanReadAsync(file).Result && file.RootFolderType != FolderType.BUNCH)
{
//No rights in CRM after upload before attach
throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
}
if (file.ContentLength > setupInfo.AvailableFileSize)
{
throw new Exception(string.Format(FilesCommonResource.ErrorMassage_FileSizeConvert, FileSizeComment.FilesSizeToString(setupInfo.AvailableFileSize)));
}
fileUri = pathProvider.GetFileStreamUrl(file);
var toExtension = fileUtility.GetInternalExtension(file.Title);
var fileExtension = file.ConvertedExtension;
var docKey = documentServiceHelper.GetDocKey(file);
fileUri = documentServiceConnector.ReplaceCommunityAdress(fileUri);
(operationResultProgress, convertedFileUrl) = documentServiceConnector.GetConvertedUriAsync(fileUri, fileExtension, toExtension, docKey, password, null, null, true).Result;
}
catch (Exception exception)
{
var password1 = exception.InnerException is DocumentServiceException documentServiceException
&& documentServiceException.Code == DocumentServiceException.ErrorCode.ConvertPassword;
logger.ErrorConvertFileWithUrl(file.Id.ToString(), fileUri, exception);
var operationResult = converter;
if (operationResult.Delete)
{
_conversionQueue.Remove(operationResult);
}
else
{
operationResult.Progress = 100;
operationResult.StopDateTime = DateTime.UtcNow;
operationResult.Error = exception.Message;
if (password1)
{
operationResult.Result = "password";
}
}
continue;
}
operationResultProgress = Math.Min(operationResultProgress, 100);
if (operationResultProgress < 100)
{
var operationResult = converter;
if (DateTime.Now - operationResult.StartDateTime > TimeSpan.FromMinutes(10))
{
operationResult.StopDateTime = DateTime.UtcNow;
operationResult.Error = FilesCommonResource.ErrorMassage_ConvertTimeout;
logger.ErrorCheckConvertFilesStatus(file.Id.ToString(), file.ContentLength);
}
else
{
operationResult.Processed = "";
}
operationResult.Progress = operationResultProgress;
logger.DebugCheckConvertFilesStatusIterationContinue();
continue;
}
File<T> newFile = null;
var operationResultError = string.Empty;
try
{
newFile = fileConverter.SaveConvertedFileAsync(file, convertedFileUrl).Result;
}
catch (Exception e)
{
operationResultError = e.Message;
logger.ErrorOperation(operationResultError, convertedFileUrl, fileUri, e);
continue;
}
finally
{
var operationResult = converter;
if (operationResult.Delete)
{
_conversionQueue.Remove(operationResult);
}
else
{
if (newFile != null)
{
var folderDao = daoFactory.GetFolderDao<T>();
var folder = folderDao.GetFolderAsync(newFile.ParentId).Result;
var folderTitle = fileSecurity.CanReadAsync(folder).Result ? folder.Title : null;
operationResult.Result = fileConverterQueue.FileJsonSerializerAsync(entryManager, newFile, folderTitle).Result;
}
operationResult.Progress = 100;
operationResult.StopDateTime = DateTime.UtcNow;
operationResult.Processed = "1";
if (!string.IsNullOrEmpty(operationResultError))
{
operationResult.Error = operationResultError;
}
}
}
logger.DebugCheckConvertFilesStatusIterationEnd();
}
fileConverterQueue.SetAllTask(_conversionQueue);
}
catch (Exception exception)
{
logger.ErrorWithException(exception);
}
}
}
public static class FileConverterQueueExtension
{
public static void Register(DIHelper services)
{
services.TryAdd<FileConverterQueueScope>();
}
}
[Scope]
public class FileConverterQueueScope
{
private readonly ILogger _options;
private readonly TenantManager _tenantManager;
private readonly UserManager _userManager;
private readonly SecurityContext _securityContext;
private readonly IDaoFactory _daoFactory;
private readonly FileSecurity _fileSecurity;
private readonly PathProvider _pathProvider;
private readonly SetupInfo _setupInfo;
private readonly FileUtility _fileUtility;
private readonly DocumentServiceHelper _documentServiceHelper;
private readonly DocumentServiceConnector _documentServiceConnector;
private readonly EntryStatusManager _entryManager;
private readonly FileConverter _fileConverter;
public FileConverterQueueScope(
ILogger<FileConverterQueueScope> options,
TenantManager tenantManager,
UserManager userManager,
SecurityContext securityContext,
IDaoFactory daoFactory,
FileSecurity fileSecurity,
PathProvider pathProvider,
SetupInfo setupInfo,
FileUtility fileUtility,
DocumentServiceHelper documentServiceHelper,
DocumentServiceConnector documentServiceConnector,
EntryStatusManager entryManager,
FileConverter fileConverter)
{
_options = options;
_tenantManager = tenantManager;
_userManager = userManager;
_securityContext = securityContext;
_daoFactory = daoFactory;
_fileSecurity = fileSecurity;
_pathProvider = pathProvider;
_setupInfo = setupInfo;
_fileUtility = fileUtility;
_documentServiceHelper = documentServiceHelper;
_documentServiceConnector = documentServiceConnector;
_entryManager = entryManager;
_fileConverter = fileConverter;
}
public void Deconstruct(out ILogger optionsMonitor,
out TenantManager tenantManager,
out UserManager userManager,
out SecurityContext securityContext,
out IDaoFactory daoFactory,
out FileSecurity fileSecurity,
out PathProvider pathProvider,
out SetupInfo setupInfo,
out FileUtility fileUtility,
out DocumentServiceHelper documentServiceHelper,
out DocumentServiceConnector documentServiceConnector,
out EntryStatusManager entryManager,
out FileConverter fileConverter)
{
optionsMonitor = _options;
tenantManager = _tenantManager;
userManager = _userManager;
securityContext = _securityContext;
daoFactory = _daoFactory;
fileSecurity = _fileSecurity;
pathProvider = _pathProvider;
setupInfo = _setupInfo;
fileUtility = _fileUtility;
documentServiceHelper = _documentServiceHelper;
documentServiceConnector = _documentServiceConnector;
entryManager = _entryManager;
fileConverter = _fileConverter;
}
}

View File

@ -25,7 +25,7 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Files.Core.Log;
internal static partial class FileConverterLogger
public static partial class FileConverterLogger
{
[LoggerMessage(Level = LogLevel.Debug, Message = "Run CheckConvertFilesStatus: count {count}")]
public static partial void DebugRunCheckConvertFilesStatus(this ILogger logger, int count);
@ -44,4 +44,11 @@ internal static partial class FileConverterLogger
[LoggerMessage(Level = LogLevel.Error, Message = "CheckConvertFilesStatus timeout: {fileId} ({contentLengthString})")]
public static partial void ErrorCheckConvertFilesStatus(this ILogger logger, string fileId, long contentLengthString);
[LoggerMessage(Level = LogLevel.Debug, Message = "FileConverterService is starting.")]
public static partial void DebugFileConverterServiceRuning(this ILogger logger);
[LoggerMessage(Level = LogLevel.Debug, Message = "FileConverterService is stopping")]
public static partial void DebugFileConverterServiceStopping(this ILogger logger);
}

View File

@ -68,6 +68,13 @@ builder.Host.ConfigureDefault(args, (hostContext, config, env, path) =>
diHelper.TryAdd<FileDataQueue>();
services.AddActivePassiveHostedService<FileConverterService<string>>();
diHelper.TryAdd<FileConverterService<string>>();
services.AddActivePassiveHostedService<FileConverterService<int>>();
diHelper.TryAdd<FileConverterService<int>>();
services.AddHostedService<ThumbnailBuilderService>();
diHelper.TryAdd<ThumbnailBuilderService>();

View File

@ -31,7 +31,7 @@
<PackageReference Include="Moq" Version="4.14.7" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
<PackageReference Include="NEST" Version="7.15.2" />
<PackageReference Include="NLog" Version="4.7.15" />
<PackageReference Include="NLog" Version="5.0.0" />
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />

View File

@ -206,113 +206,118 @@ public class MailServiceHelper
{
DemandPermission();
using var transaction = MailDbContext.Database.BeginTransaction();
var strategy = MailDbContext.Database.CreateExecutionStrategy();
var mailboxProvider = new MailboxProvider
strategy.Execute(() =>
{
Id = 0,
Name = hostname
};
using var transaction = MailDbContext.Database.BeginTransaction();
var pReq = MailDbContext.MailboxProvider.Add(mailboxProvider);
MailDbContext.SaveChanges();
mailboxProvider = pReq.Entity;
var providerId = mailboxProvider.Id;
var mailboxServer = new MailboxServer
{
Id = 0,
IdProvider = providerId,
Type = "smtp",
Hostname = hostname,
Port = 587,
SocketType = "STARTTLS",
UserName = "%EMAILADDRESS%",
Authentication = "",
IsUserData = false
};
var req = MailDbContext.MailboxServer.Add(mailboxServer);
MailDbContext.SaveChanges();
mailboxServer = req.Entity;
var smtpServerId = mailboxServer.Id;
mailboxServer = new MailboxServer
{
Id = 0,
IdProvider = providerId,
Type = "imap",
Hostname = hostname,
Port = 143,
SocketType = "STARTTLS",
UserName = "%EMAILADDRESS%",
Authentication = "",
IsUserData = false
};
req = MailDbContext.MailboxServer.Add(mailboxServer);
MailDbContext.SaveChanges();
mailboxServer = req.Entity;
var imapServerId = mailboxServer.Id;
var mailServerData = MailDbContext.ServerServer.FirstOrDefault();
var connectionString = JsonConvert.SerializeObject(mailServer);
var server = new ServerServer
{
Id = 0,
MxRecord = hostname,
ConnectionString = connectionString,
ServerType = 2,
SmtpSettingsId = smtpServerId,
ImapSettingsId = imapServerId
};
MailDbContext.ServerServer.Add(server);
MailDbContext.SaveChanges();
if (mailServerData != null)
{
server = MailDbContext.ServerServer.Where(r => r.Id == mailServerData.Id).FirstOrDefault();
MailDbContext.ServerServer.Remove(server);
MailDbContext.SaveChanges();
providerId = MailDbContext.MailboxServer
.Where(r => r.Id == mailServerData.SmtpSettingsId)
.Select(r => r.IdProvider)
.FirstOrDefault();
var providers = MailDbContext.MailboxProvider.Where(r => r.Id == providerId).ToList();
MailDbContext.MailboxProvider.RemoveRange(providers);
MailDbContext.SaveChanges();
var servers = MailDbContext.MailboxServer
.Where(r => new[] { mailServerData.SmtpSettingsId, mailServerData.ImapSettingsId }.Any(a => a == r.Id))
.ToList();
MailDbContext.MailboxServer.RemoveRange(servers);
MailDbContext.SaveChanges();
var mailboxId = MailDbContext.Mailbox
.Where(r => r.IdSmtpServer == mailServerData.SmtpSettingsId)
.Where(r => r.IdInServer == mailServerData.ImapSettingsId)
.ToArray();
foreach (var m in mailboxId)
var mailboxProvider = new MailboxProvider
{
m.IdSmtpServer = smtpServerId;
m.IdInServer = imapServerId;
}
MailDbContext.SaveChanges();
}
Id = 0,
Name = hostname
};
transaction.Commit();
var pReq = MailDbContext.MailboxProvider.Add(mailboxProvider);
MailDbContext.SaveChanges();
mailboxProvider = pReq.Entity;
var providerId = mailboxProvider.Id;
var mailboxServer = new MailboxServer
{
Id = 0,
IdProvider = providerId,
Type = "smtp",
Hostname = hostname,
Port = 587,
SocketType = "STARTTLS",
UserName = "%EMAILADDRESS%",
Authentication = "",
IsUserData = false
};
var req = MailDbContext.MailboxServer.Add(mailboxServer);
MailDbContext.SaveChanges();
mailboxServer = req.Entity;
var smtpServerId = mailboxServer.Id;
mailboxServer = new MailboxServer
{
Id = 0,
IdProvider = providerId,
Type = "imap",
Hostname = hostname,
Port = 143,
SocketType = "STARTTLS",
UserName = "%EMAILADDRESS%",
Authentication = "",
IsUserData = false
};
req = MailDbContext.MailboxServer.Add(mailboxServer);
MailDbContext.SaveChanges();
mailboxServer = req.Entity;
var imapServerId = mailboxServer.Id;
var mailServerData = MailDbContext.ServerServer.FirstOrDefault();
var connectionString = JsonConvert.SerializeObject(mailServer);
var server = new ServerServer
{
Id = 0,
MxRecord = hostname,
ConnectionString = connectionString,
ServerType = 2,
SmtpSettingsId = smtpServerId,
ImapSettingsId = imapServerId
};
MailDbContext.ServerServer.Add(server);
MailDbContext.SaveChanges();
if (mailServerData != null)
{
server = MailDbContext.ServerServer.Where(r => r.Id == mailServerData.Id).FirstOrDefault();
MailDbContext.ServerServer.Remove(server);
MailDbContext.SaveChanges();
providerId = MailDbContext.MailboxServer
.Where(r => r.Id == mailServerData.SmtpSettingsId)
.Select(r => r.IdProvider)
.FirstOrDefault();
var providers = MailDbContext.MailboxProvider.Where(r => r.Id == providerId).ToList();
MailDbContext.MailboxProvider.RemoveRange(providers);
MailDbContext.SaveChanges();
var servers = MailDbContext.MailboxServer
.Where(r => new[] { mailServerData.SmtpSettingsId, mailServerData.ImapSettingsId }.Any(a => a == r.Id))
.ToList();
MailDbContext.MailboxServer.RemoveRange(servers);
MailDbContext.SaveChanges();
var mailboxId = MailDbContext.Mailbox
.Where(r => r.IdSmtpServer == mailServerData.SmtpSettingsId)
.Where(r => r.IdInServer == mailServerData.ImapSettingsId)
.ToArray();
foreach (var m in mailboxId)
{
m.IdSmtpServer = smtpServerId;
m.IdInServer = imapServerId;
}
MailDbContext.SaveChanges();
}
transaction.Commit();
});
_mailServiceHelperStorage.Remove();
}

View File

@ -131,27 +131,33 @@ public class StatisticManager
_lastSave = DateTime.UtcNow;
}
using var tx = WebstudioDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
foreach (var v in visits)
var strategy = WebstudioDbContext.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
var w = new DbWebstudioUserVisit
{
TenantId = v.TenantID,
ProductId = v.ProductID,
UserId = v.UserID,
VisitDate = v.VisitDate.Date,
FirstVisitTime = v.VisitDate,
VisitCount = v.VisitCount
};
using var tx = WebstudioDbContext.Database.BeginTransaction(IsolationLevel.ReadUncommitted);
if (v.LastVisitTime.HasValue)
foreach (var v in visits)
{
w.LastVisitTime = v.LastVisitTime.Value;
var w = new DbWebstudioUserVisit
{
TenantId = v.TenantID,
ProductId = v.ProductID,
UserId = v.UserID,
VisitDate = v.VisitDate.Date,
FirstVisitTime = v.VisitDate,
VisitCount = v.VisitCount
};
if (v.LastVisitTime.HasValue)
{
w.LastVisitTime = v.LastVisitTime.Value;
}
WebstudioDbContext.WebstudioUserVisit.Add(w);
WebstudioDbContext.SaveChanges();
}
WebstudioDbContext.WebstudioUserVisit.Add(w);
WebstudioDbContext.SaveChanges();
}
tx.Commit();
tx.Commit();
});
}
}