DocSpace-buildtools/common/ASC.Feed/Data/FeedAggregateDataProvider.cs

376 lines
13 KiB
C#
Raw Normal View History

2022-03-15 18:00:53 +00:00
// (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
2022-02-10 18:39:04 +00:00
namespace ASC.Feed.Data;
[Scope]
public class FeedAggregateDataProvider
{
2022-02-10 18:39:04 +00:00
private readonly AuthContext _authContext;
private readonly TenantManager _tenantManager;
2022-03-17 15:07:17 +00:00
private readonly IMapper _mapper;
2022-07-28 18:00:49 +00:00
private readonly IDbContextFactory<FeedDbContext> _dbContextFactory;
2022-02-10 18:39:04 +00:00
public FeedAggregateDataProvider(
AuthContext authContext,
TenantManager tenantManager,
2022-07-28 18:00:49 +00:00
IDbContextFactory<FeedDbContext> dbContextFactory,
2022-02-10 18:39:04 +00:00
IMapper mapper)
2022-04-14 19:23:57 +00:00
: this(authContext, tenantManager, mapper)
{
2022-07-28 18:00:49 +00:00
_dbContextFactory = dbContextFactory;
2022-02-10 18:39:04 +00:00
}
2019-12-10 08:54:53 +00:00
2022-02-10 18:39:04 +00:00
public FeedAggregateDataProvider(
AuthContext authContext,
TenantManager tenantManager,
IMapper mapper)
{
_authContext = authContext;
_tenantManager = tenantManager;
_mapper = mapper;
}
2019-10-10 08:52:21 +00:00
2022-02-10 18:39:04 +00:00
public DateTime GetLastTimeAggregate(string key)
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
var value = feedDbContext.FeedLast.Where(r => r.LastKey == key).Select(r => r.LastDate).FirstOrDefault();
2022-02-10 18:39:04 +00:00
return value != default ? value.AddSeconds(1) : value;
}
2022-09-09 10:38:13 +00:00
public void SaveFeeds(IEnumerable<FeedRow> feeds, string key, DateTime value, int portionSize)
2022-02-10 18:39:04 +00:00
{
var feedLast = new FeedLast
{
2022-02-10 18:39:04 +00:00
LastKey = key,
LastDate = value
};
2019-12-09 11:59:22 +00:00
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
2022-12-21 12:57:32 +00:00
feedDbContext.AddOrUpdate(feedDbContext.FeedLast, feedLast);
2022-07-28 18:00:49 +00:00
feedDbContext.SaveChanges();
2022-02-10 18:39:04 +00:00
var aggregatedDate = DateTime.UtcNow;
2022-02-10 18:39:04 +00:00
var feedsPortion = new List<FeedRow>();
foreach (var feed in feeds)
{
feedsPortion.Add(feed);
2022-09-09 10:38:13 +00:00
if (feedsPortion.Sum(f => f.Users.Count) <= portionSize)
{
2022-02-10 18:39:04 +00:00
continue;
}
2022-02-10 16:59:02 +00:00
2022-02-10 18:39:04 +00:00
SaveFeedsPortion(feedsPortion, aggregatedDate);
feedsPortion.Clear();
}
2022-02-10 18:39:04 +00:00
if (feedsPortion.Count > 0)
{
2022-02-10 18:39:04 +00:00
SaveFeedsPortion(feedsPortion, aggregatedDate);
}
}
2019-08-15 15:08:40 +00:00
2022-02-10 18:39:04 +00:00
private void SaveFeedsPortion(IEnumerable<FeedRow> feeds, DateTime aggregatedDate)
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
var strategy = feedDbContext.Database.CreateExecutionStrategy();
2019-08-15 15:08:40 +00:00
strategy.Execute(async () =>
2022-02-10 18:39:04 +00:00
{
2023-03-10 13:09:32 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
using var tx = await feedDbContext.Database.BeginTransactionAsync();
foreach (var f in feeds)
{
if (0 >= f.Users.Count)
{
continue;
}
var feedAggregate = _mapper.Map<FeedRow, FeedAggregate>(f);
feedAggregate.AggregateDate = aggregatedDate;
if (f.ClearRightsBeforeInsert)
2019-08-15 15:08:40 +00:00
{
var fu = await feedDbContext.FeedUsers.Where(r => r.FeedId == f.Id).FirstOrDefaultAsync();
if (fu != null)
{
2022-07-28 18:00:49 +00:00
feedDbContext.FeedUsers.Remove(fu);
}
2019-08-15 15:08:40 +00:00
}
await feedDbContext.AddOrUpdateAsync(r => feedDbContext.FeedAggregates, feedAggregate);
2019-12-23 13:36:37 +00:00
foreach (var u in f.Users)
2019-08-15 15:08:40 +00:00
{
var feedUser = new FeedUsers
{
FeedId = f.Id,
UserId = u
};
2019-12-09 11:59:22 +00:00
await feedDbContext.AddOrUpdateAsync(r => feedDbContext.FeedUsers, feedUser);
}
2019-08-15 15:08:40 +00:00
}
await feedDbContext.SaveChangesAsync();
await tx.CommitAsync();
2023-03-10 13:09:32 +00:00
}).GetAwaiter()
.GetResult();
2022-02-10 18:39:04 +00:00
}
2022-02-10 18:39:04 +00:00
public void RemoveFeedAggregate(DateTime fromTime)
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
var strategy = feedDbContext.Database.CreateExecutionStrategy();
strategy.Execute(async () =>
{
2023-03-10 13:09:32 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
using var tx = await feedDbContext.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted);
2019-12-09 11:59:22 +00:00
await feedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime).ExecuteDeleteAsync();
await feedDbContext.FeedUsers.Where(r => feedDbContext.FeedAggregates.Where(r => r.AggregateDate <= fromTime).Any(a => a.Id == r.FeedId)).ExecuteDeleteAsync();
2019-12-09 11:59:22 +00:00
await tx.CommitAsync();
2023-03-10 13:09:32 +00:00
}).GetAwaiter()
.GetResult();
2022-02-10 18:39:04 +00:00
}
2022-02-10 18:39:04 +00:00
public List<FeedResultItem> GetFeeds(FeedApiFilter filter)
{
var filterOffset = filter.Offset;
var filterLimit = filter.Max > 0 && filter.Max < 1000 ? filter.Max : 1000;
2022-02-10 18:39:04 +00:00
var feeds = new Dictionary<string, List<FeedResultItem>>();
2022-02-10 18:39:04 +00:00
var tryCount = 0;
List<FeedResultItem> feedsIteration;
do
{
2022-02-10 18:39:04 +00:00
feedsIteration = GetFeedsInternal(filter);
foreach (var feed in feedsIteration)
{
2022-02-10 18:39:04 +00:00
if (feeds.TryGetValue(feed.GroupId, out var value))
{
2022-02-10 18:39:04 +00:00
value.Add(feed);
}
2022-02-10 18:39:04 +00:00
else
{
2022-02-10 18:39:04 +00:00
feeds[feed.GroupId] = new List<FeedResultItem> { feed };
}
}
2022-02-10 18:39:04 +00:00
filter.Offset += feedsIteration.Count;
} while (feeds.Count < filterLimit
&& feedsIteration.Count == filterLimit
&& tryCount++ < 5);
2022-02-10 18:39:04 +00:00
filter.Offset = filterOffset;
2019-12-10 08:54:53 +00:00
2022-02-10 18:39:04 +00:00
return feeds.Take(filterLimit).SelectMany(group => group.Value).ToList();
}
2022-03-01 16:45:27 +00:00
private List<FeedResultItem> GetFeedsInternal(FeedApiFilter filter)
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
2022-09-02 08:31:04 +00:00
var q = feedDbContext.FeedAggregates.AsNoTracking()
2022-09-02 15:59:52 +00:00
.Where(r => r.Tenant == _tenantManager.GetCurrentTenant().Id);
2022-09-02 15:59:52 +00:00
var exp = GetIdSearchExpression(filter.Id, filter.Module, filter.WithRelated);
2022-09-02 15:59:52 +00:00
if (exp != null)
{
2022-09-02 15:59:52 +00:00
q = q.Where(exp);
}
2022-09-02 15:59:52 +00:00
var q1 = q.Join(feedDbContext.FeedUsers, a => a.Id, b => b.FeedId, (aggregates, users) => new { aggregates, users })
.OrderByDescending(r => r.aggregates.ModifiedDate)
.Skip(filter.Offset)
.Take(filter.Max);
if (exp == null)
{
2022-09-02 15:59:52 +00:00
q1 = q1.Where(r => r.aggregates.ModifiedBy != _authContext.CurrentAccount.ID).
Where(r => r.users.UserId == _authContext.CurrentAccount.ID);
}
2022-02-10 18:39:04 +00:00
if (filter.OnlyNew)
{
2022-09-02 15:59:52 +00:00
q1 = q1.Where(r => r.aggregates.AggregateDate >= filter.From);
2022-02-10 18:39:04 +00:00
}
else
{
if (1 < filter.From.Year)
{
2022-09-02 15:59:52 +00:00
q1 = q1.Where(r => r.aggregates.ModifiedDate >= filter.From);
}
2022-02-10 18:39:04 +00:00
if (filter.To.Year < 9999)
{
2022-09-02 15:59:52 +00:00
q1 = q1.Where(r => r.aggregates.ModifiedDate <= filter.To);
}
}
2019-12-10 08:54:53 +00:00
2022-02-10 18:39:04 +00:00
if (!string.IsNullOrEmpty(filter.Product))
{
2022-09-02 15:59:52 +00:00
q1 = q1.Where(r => r.aggregates.Product == filter.Product);
}
2019-12-10 08:54:53 +00:00
2022-02-10 18:39:04 +00:00
if (filter.Author != Guid.Empty)
{
2022-09-02 15:59:52 +00:00
q1 = q1.Where(r => r.aggregates.ModifiedBy == filter.Author);
}
2019-12-10 08:54:53 +00:00
2022-02-10 18:39:04 +00:00
if (filter.SearchKeys != null && filter.SearchKeys.Length > 0)
{
2022-02-10 18:39:04 +00:00
var keys = filter.SearchKeys
.Where(s => !string.IsNullOrEmpty(s))
.Select(s => s.Replace("\\", "\\\\").Replace("%", "\\%").Replace("_", "\\_"))
.ToList();
2022-09-02 15:59:52 +00:00
q1 = q1.Where(r => keys.Any(k => r.aggregates.Keywords.StartsWith(k)));
}
var news = q1.Select(r => r.aggregates).Distinct().AsEnumerable();
2022-02-10 18:39:04 +00:00
return _mapper.Map<IEnumerable<FeedAggregate>, List<FeedResultItem>>(news);
}
2022-09-01 15:19:17 +00:00
public int GetNewFeedsCount(DateTime lastReadedTime)
2022-03-01 16:45:27 +00:00
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
var count = feedDbContext.FeedAggregates
2022-09-01 15:19:17 +00:00
.Where(r => r.Tenant == _tenantManager.GetCurrentTenant().Id)
.Where(r => r.ModifiedBy != _authContext.CurrentAccount.ID)
2022-07-28 18:00:49 +00:00
.Join(feedDbContext.FeedUsers, r => r.Id, u => u.FeedId, (agg, user) => new { agg, user })
2022-09-01 15:19:17 +00:00
.Where(r => r.user.UserId == _authContext.CurrentAccount.ID);
2019-08-15 12:04:42 +00:00
2022-02-10 18:39:04 +00:00
if (1 < lastReadedTime.Year)
{
2022-02-10 18:39:04 +00:00
count = count.Where(r => r.agg.AggregateDate >= lastReadedTime);
}
2022-02-10 18:39:04 +00:00
return count.Take(1001).Select(r => r.agg.Id).Count();
}
2022-02-10 18:39:04 +00:00
public IEnumerable<int> GetTenants(TimeInterval interval)
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
return feedDbContext.FeedAggregates
2022-02-10 18:39:04 +00:00
.Where(r => r.AggregateDate >= interval.From && r.AggregateDate <= interval.To)
.GroupBy(r => r.Tenant)
.Select(r => r.Key)
.ToList();
}
2022-04-14 19:23:57 +00:00
public FeedResultItem GetFeedItem(string id)
2022-02-10 18:39:04 +00:00
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
2022-02-10 18:39:04 +00:00
var news =
2022-07-28 18:00:49 +00:00
feedDbContext.FeedAggregates
2022-02-10 18:39:04 +00:00
.Where(r => r.Id == id)
.FirstOrDefault();
2022-02-10 18:39:04 +00:00
return _mapper.Map<FeedAggregate, FeedResultItem>(news);
}
2022-02-10 18:39:04 +00:00
public void RemoveFeedItem(string id)
{
2022-07-28 18:00:49 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
var strategy = feedDbContext.Database.CreateExecutionStrategy();
strategy.Execute(async () =>
{
2023-03-10 13:09:32 +00:00
using var feedDbContext = _dbContextFactory.CreateDbContext();
using var tx = await feedDbContext.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted);
await feedDbContext.FeedAggregates.Where(r => r.Id == id).ExecuteDeleteAsync();
await feedDbContext.FeedUsers.Where(r => r.FeedId == id).ExecuteDeleteAsync();
await tx.CommitAsync();
2023-03-10 13:09:32 +00:00
}).GetAwaiter()
.GetResult();
2022-02-10 18:39:04 +00:00
}
2022-09-02 15:59:52 +00:00
private Expression<Func<FeedAggregate, bool>> GetIdSearchExpression(string id, string module, bool withRelated)
{
Expression<Func<FeedAggregate, bool>> exp = null;
if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(module))
{
return exp;
}
if (module == Constants.RoomsModule)
{
var roomId = $"{Constants.RoomItem}_{id}";
var sharedRoomId = $"{Constants.SharedRoomItem}_{id}";
exp = f => f.Id == roomId || f.Id.StartsWith(sharedRoomId);
if (withRelated)
{
exp = f => f.Id == roomId || f.Id.StartsWith(sharedRoomId) || f.ContextId == roomId;
}
}
if (module == Constants.FilesModule)
{
exp = f => f.Id.StartsWith($"{Constants.FileItem}_{id}") || f.Id.StartsWith($"{Constants.SharedFileItem}_{id}");
}
if (module == Constants.FoldersModule)
{
exp = f => f.Id == $"{Constants.FolderItem}_{id}" || f.Id.StartsWith($"{Constants.SharedFolderItem}_{id}");
}
return exp;
}
2022-02-10 18:39:04 +00:00
}
2022-02-10 18:39:04 +00:00
public class FeedResultItem : IMapFrom<FeedAggregate>
{
2022-09-01 15:19:17 +00:00
public string Json { get; set; }
public string Module { get; set; }
public Guid AuthorId { get; set; }
public Guid ModifiedBy { get; set; }
public object TargetId { get; set; }
2022-09-01 15:19:17 +00:00
public string GroupId { get; set; }
public bool IsToday { get; set; }
public bool IsYesterday { get; set; }
public bool IsTomorrow { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime ModifiedDate { get; set; }
public DateTime AggregatedDate { get; set; }
2022-02-10 18:39:04 +00:00
public void Mapping(Profile profile)
{
profile.CreateMap<FeedAggregate, FeedResultItem>()
2022-09-01 15:19:17 +00:00
.AfterMap<FeedMappingAction>();
}
2022-09-01 15:19:17 +00:00
}