optimized access check

This commit is contained in:
Maksim Chegulov 2023-09-04 20:10:13 +03:00
parent e5b3d44bc3
commit 7f9286219c
4 changed files with 85 additions and 40 deletions

View File

@ -276,15 +276,14 @@ internal abstract class SecurityBaseDao<T> : AbstractDao
return result;
}
internal async Task<FileShareRecord> ToFileShareRecordAsync(SecurityTreeRecord r)
protected FileShareRecord ToFileShareRecord(SecurityTreeRecord r)
{
var result = await ToFileShareRecordAsync(r.DbFilesSecurity);
if (r.DbFolderTree != null)
{
result.EntryId = r.DbFolderTree.FolderId;
}
var result = _mapper.Map<SecurityTreeRecord, FileShareRecord>(r);
result.Level = r.DbFolderTree?.Level ?? -1;
if (r.FolderId != default)
{
result.EntryId = r.FolderId;
}
return result;
}
@ -309,7 +308,7 @@ internal class SecurityDao : SecurityBaseDao<int>, ISecurityDao<int>
{
}
public async Task<IEnumerable<FileShareRecord>> GetSharesAsync(FileEntry<int> entry)
public async Task<IEnumerable<FileShareRecord>> GetSharesAsync(FileEntry<int> entry, IEnumerable<Guid> subjects = null)
{
if (entry == null)
{
@ -321,30 +320,56 @@ internal class SecurityDao : SecurityBaseDao<int>, ISecurityDao<int>
await SelectFilesAndFoldersForShareAsync(entry, files, null, foldersInt);
return await SaveFilesAndFoldersForShareAsync(files, foldersInt);
}
private async Task<IEnumerable<FileShareRecord>> SaveFilesAndFoldersForShareAsync(List<string> files, List<int> folders)
{
await using var filesDbContext = _dbContextFactory.CreateDbContext();
var q = await Query(filesDbContext.Security)
.Join(filesDbContext.Tree, r => r.EntryId, a => a.ParentId.ToString(), (security, tree) => new SecurityTreeRecord { DbFilesSecurity = security, DbFolderTree = tree })
.Where(r => folders.Contains(r.DbFolderTree.FolderId) &&
r.DbFilesSecurity.EntryType == FileEntryType.Folder)
.ToListAsync();
var q = Query(filesDbContext.Security)
.Join(filesDbContext.Tree, r => r.EntryId, a => a.ParentId.ToString(),
(s, t) => new SecurityTreeRecord
{
TenantId = s.TenantId,
EntryId = s.EntryId,
EntryType = s.EntryType,
SubjectType = s.SubjectType,
Subject = s.Subject,
Owner = s.Owner,
Share = s.Share,
TimeStamp = s.TimeStamp,
Options = s.Options,
FolderId = t.FolderId,
ParentId = t.ParentId,
Level = t.Level
})
.Where(r => foldersInt.Contains(r.FolderId) && r.EntryType == FileEntryType.Folder);
if (0 < files.Count)
if (files.Count > 0)
{
var q1 = await GetQuery(filesDbContext, r => files.Contains(r.EntryId) && r.EntryType == FileEntryType.File)
.Select(r => new SecurityTreeRecord { DbFilesSecurity = r })
.ToListAsync();
q = q.Union(q1).ToList();
var q1 = GetQuery(filesDbContext, r => files.Contains(r.EntryId) && r.EntryType == FileEntryType.File)
.Select(s => new SecurityTreeRecord
{
TenantId = s.TenantId,
EntryId = s.EntryId,
EntryType = s.EntryType,
SubjectType = s.SubjectType,
Subject = s.Subject,
Owner = s.Owner,
Share = s.Share,
TimeStamp = s.TimeStamp,
Options = s.Options,
FolderId = 0,
ParentId = 0,
Level = -1
});
q = q.Concat(q1);
}
var records = await q
.ToAsyncEnumerable()
.SelectAwait(async e => await ToFileShareRecordAsync(e))
if (subjects != null && subjects.Any())
{
q = q.Where(r => subjects.Contains(r.Subject));
}
var records = await q.ToAsyncEnumerable()
.Select(ToFileShareRecord)
.OrderBy(r => r.Level)
.ThenByDescending(r => r.Share, new FileShareRecord.ShareComparer())
.ToListAsync();
@ -404,7 +429,7 @@ internal class ThirdPartySecurityDao : SecurityBaseDao<string>, ISecurityDao<str
_selectorFactory = selectorFactory;
}
public async Task<IEnumerable<FileShareRecord>> GetSharesAsync(FileEntry<string> entry)
public async Task<IEnumerable<FileShareRecord>> GetSharesAsync(FileEntry<string> entry, IEnumerable<Guid> subjects = null)
{
var result = new List<FileShareRecord>();
@ -433,6 +458,11 @@ internal class ThirdPartySecurityDao : SecurityBaseDao<string>, ISecurityDao<str
result.AddRange(await GetShareForFoldersAsync(folders).ToListAsync());
if (subjects != null && subjects.Any())
{
result = result.Where(r => subjects.Contains(r.Subject)).ToList();
}
return result;
}
@ -494,11 +524,20 @@ internal class ThirdPartySecurityDao : SecurityBaseDao<string>, ISecurityDao<str
}
}
}
internal class SecurityTreeRecord
{
public DbFilesSecurity DbFilesSecurity { get; init; }
public DbFolderTree DbFolderTree { get; init; }
public int TenantId { get; set; }
public string EntryId { get; set; }
public FileEntryType EntryType { get; set; }
public SubjectType SubjectType { get; set; }
public Guid Subject { get; set; }
public Guid Owner { get; set; }
public FileShare Share { get; set; }
public DateTime TimeStamp { get; set; }
public string Options { get; set; }
public int FolderId { get; set; }
public int ParentId { get; set; }
public int Level { get; set; }
}
static file class Queries

View File

@ -931,10 +931,7 @@ public class FileSecurity : IFileSecurity
if (shares == null)
{
subjects = await GetUserSubjectsAsync(userId);
shares = (await GetSharesAsync(e))
.Join(subjects, r => r.Subject, s => s, (r, s) => r)
.ToList();
// shares ordered by level
shares = await GetSharesAsync(e, subjects);
}
if (e.FileEntryType == FileEntryType.File)
@ -1176,9 +1173,9 @@ public class FileSecurity : IFileSecurity
await securityDao.SetShareAsync(r);
}
public async Task<IEnumerable<FileShareRecord>> GetSharesAsync<T>(FileEntry<T> entry)
public async Task<IEnumerable<FileShareRecord>> GetSharesAsync<T>(FileEntry<T> entry, IEnumerable<Guid> subjects = null)
{
return await _daoFactory.GetSecurityDao<T>().GetSharesAsync(entry);
return await _daoFactory.GetSecurityDao<T>().GetSharesAsync(entry, subjects);
}
public async IAsyncEnumerable<FileEntry> GetSharesForMeAsync(FilterType filterType, bool subjectGroup, Guid subjectID, string searchText = "", bool searchInContent = false, bool withSubfolders = false)
@ -1731,6 +1728,11 @@ public class FileSecurity : IFileSecurity
.Where(f => DocSpaceHelper.IsRoom(f.FolderType))
.FirstOrDefaultAsync();
if (room == null)
{
return false;
}
_cachedRoomOwner.TryAdd(GetCacheKey(entry.ParentId), room.CreateBy);
return room.CreateBy == userId;

View File

@ -32,7 +32,7 @@ public interface ISecurityDao<T>
Task SetShareAsync(FileShareRecord r);
IAsyncEnumerable<FileShareRecord> GetShareForEntryIdsAsync(Guid subject, IEnumerable<string> roomIds);
IAsyncEnumerable<FileShareRecord> GetSharesAsync(IEnumerable<Guid> subjects);
Task<IEnumerable<FileShareRecord>> GetSharesAsync(FileEntry<T> entry);
Task<IEnumerable<FileShareRecord>> GetSharesAsync(FileEntry<T> entry, IEnumerable<Guid> subjects = null);
Task RemoveSubjectAsync(Guid subject);
IAsyncEnumerable<FileShareRecord> GetPureShareRecordsAsync(IEnumerable<FileEntry<T>> entries);
IAsyncEnumerable<FileShareRecord> GetPureShareRecordsAsync(FileEntry<T> entry);

View File

@ -59,5 +59,9 @@ public class FilesMappingProfile : AutoMapper.Profile
CreateMap<DbFilesSecurity, FileShareRecord>()
.ForMember(dest => dest.Options, cfg =>
cfg.MapFrom(src => JsonSerializer.Deserialize<FileShareOptions>(src.Options, JsonSerializerOptions.Default)));
CreateMap<SecurityTreeRecord, FileShareRecord>()
.ForMember(dest => dest.Options, cfg =>
cfg.MapFrom(src => JsonSerializer.Deserialize<FileShareOptions>(src.Options, JsonSerializerOptions.Default)));
}
}