diff --git a/common/services/ASC.ElasticSearch/Core/Selector.cs b/common/services/ASC.ElasticSearch/Core/Selector.cs index f9def20867..326aac2c28 100644 --- a/common/services/ASC.ElasticSearch/Core/Selector.cs +++ b/common/services/ASC.ElasticSearch/Core/Selector.cs @@ -168,7 +168,15 @@ public Selector MatchAll(string value) return this; } - + + public Selector Nested(Expression> fieldSelector, Func, QueryContainer> selector) + { + var path = IsNested(fieldSelector); + _queryContainer &= _queryContainerDescriptor.Nested(a => a.Query(selector).Path(char.ToLower(path[0]) + path[1..])); + + return this; + } + public Selector Sort(Expression> selector, bool asc) { _sortContainerDescriptor = _sortContainerDescriptor.Field(selector, asc ? SortOrder.Ascending : SortOrder.Descending); @@ -367,6 +375,11 @@ private string IsNested(Field selector) return null; } + if (lambdaExpression.Body is MemberExpression memberExpression && memberExpression.Member.GetCustomAttributes(false).OfType().Any()) + { + return memberExpression.Member.Name; + } + if (lambdaExpression.Body is MethodCallExpression { Arguments.Count: > 1 } methodCallExpression) { return methodCallExpression.Arguments[0] is not MemberExpression pathMember diff --git a/common/services/ASC.ElasticSearch/Engine/Client.cs b/common/services/ASC.ElasticSearch/Engine/Client.cs index 4c8ed4cc24..7e39cfff76 100644 --- a/common/services/ASC.ElasticSearch/Engine/Client.cs +++ b/common/services/ASC.ElasticSearch/Engine/Client.cs @@ -73,12 +73,12 @@ public OpenSearchClient Instance { connectionSettings.DisableDirectStreaming().PrettyJson().EnableDebugMode(r => { - // _logger.Debug(r.DebugInformation); - // - // if (r.RequestBodyInBytes != null) - // { - // _logger.Debug($"Request: {Encoding.UTF8.GetString(r.RequestBodyInBytes)}"); - // } + logger.Debug(r.DebugInformation); + + if (r.RequestBodyInBytes != null) + { + logger.Debug($"Request: {Encoding.UTF8.GetString(r.RequestBodyInBytes)}"); + } if (r.HttpStatusCode is 403 or 500 && r.ResponseBodyInBytes != null) { diff --git a/products/ASC.Files/Core/ApiModels/RequestDto/GetFolderRequestDto.cs b/products/ASC.Files/Core/ApiModels/RequestDto/GetFolderRequestDto.cs index b8af7c8787..6bed7d6c5d 100644 --- a/products/ASC.Files/Core/ApiModels/RequestDto/GetFolderRequestDto.cs +++ b/products/ASC.Files/Core/ApiModels/RequestDto/GetFolderRequestDto.cs @@ -87,6 +87,13 @@ public class GetFolderRequestDto /// [FromQuery(Name = "searchArea")] public SearchArea SearchArea { get; set; } + + + [FromQuery(Name = "formsItemKey")] + public string FormsItemKey { get; set; } + + [FromQuery(Name = "formsItemType")] + public string FormsItemType{ get; set; } } /// diff --git a/products/ASC.Files/Core/ApiModels/ResponseDto/FolderContentDto.cs b/products/ASC.Files/Core/ApiModels/ResponseDto/FolderContentDto.cs index 39cf76adf9..671bbe32e8 100644 --- a/products/ASC.Files/Core/ApiModels/ResponseDto/FolderContentDto.cs +++ b/products/ASC.Files/Core/ApiModels/ResponseDto/FolderContentDto.cs @@ -85,11 +85,11 @@ public class FolderContentDtoHelper( AuthContext authContext, BreadCrumbsManager breadCrumbsManager) { - public async Task> GetAsync(T folderId, Guid? userIdOrGroupId, FilterType? filterType, T roomId, bool? searchInContent, bool? withSubFolders, bool? excludeSubject, ApplyFilterOption? applyFilterOption, SearchArea? searchArea, string[] extension = null) + public async Task> GetAsync(T folderId, Guid? userIdOrGroupId, FilterType? filterType, T roomId, bool? searchInContent, bool? withSubFolders, bool? excludeSubject, ApplyFilterOption? applyFilterOption, SearchArea? searchArea, string[] extension = null, FormsItemDto formsItemDto = null) { var types = filterType.HasValue ? new[] { filterType.Value } : null; - - var folderContentWrapper = await ToFolderContentWrapperAsync(folderId, userIdOrGroupId ?? Guid.Empty, types, roomId, searchInContent ?? false, withSubFolders ?? false, excludeSubject ?? false, applyFilterOption ?? ApplyFilterOption.All, extension, searchArea ?? SearchArea.Active); + + var folderContentWrapper = await ToFolderContentWrapperAsync(folderId, userIdOrGroupId ?? Guid.Empty, types, roomId, searchInContent ?? false, withSubFolders ?? false, excludeSubject ?? false, applyFilterOption ?? ApplyFilterOption.All, extension, searchArea ?? SearchArea.Active, formsItemDto); return folderContentWrapper.NotFoundIfNull(); } @@ -221,7 +221,7 @@ await fileSecurityCommon.IsDocSpaceAdministratorAsync(authContext.CurrentAccount } } - private async Task> ToFolderContentWrapperAsync(T folderId, Guid userIdOrGroupId, IEnumerable filterTypes, T roomId, bool searchInContent, bool withSubFolders, bool excludeSubject, ApplyFilterOption applyFilterOption, string[] extension, SearchArea searchArea) + private async Task> ToFolderContentWrapperAsync(T folderId, Guid userIdOrGroupId, IEnumerable filterTypes, T roomId, bool searchInContent, bool withSubFolders, bool excludeSubject, ApplyFilterOption applyFilterOption, string[] extension, SearchArea searchArea, FormsItemDto formsItemDto) { OrderBy orderBy = null; if (SortedByTypeExtensions.TryParse(apiContext.SortBy, true, out var sortBy)) @@ -231,7 +231,7 @@ private async Task> ToFolderContentWrapperAsync(T folderI var startIndex = Convert.ToInt32(apiContext.StartIndex); var items = await fileStorageService.GetFolderItemsAsync(folderId, startIndex, Convert.ToInt32(apiContext.Count), filterTypes, filterTypes?.FirstOrDefault() == FilterType.ByUser, userIdOrGroupId.ToString(), apiContext.FilterValue, extension, searchInContent, withSubFolders, orderBy, excludeSubject: excludeSubject, - roomId: roomId, applyFilterOption: applyFilterOption, searchArea: searchArea); + roomId: roomId, applyFilterOption: applyFilterOption, searchArea: searchArea, formsItemDto: formsItemDto); return await GetAsync(folderId, items, startIndex); } diff --git a/products/ASC.Files/Core/ApiModels/ResponseDto/FormsItemDto.cs b/products/ASC.Files/Core/ApiModels/ResponseDto/FormsItemDto.cs new file mode 100644 index 0000000000..6eafa8a7a6 --- /dev/null +++ b/products/ASC.Files/Core/ApiModels/ResponseDto/FormsItemDto.cs @@ -0,0 +1,29 @@ +// (c) Copyright Ascensio System SIA 2009-2024 +// +// 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.Files.Core.ApiModels.ResponseDto; + +public record FormsItemDto(string Key, string Type); \ No newline at end of file diff --git a/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs b/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs index 3089d552cf..cae21f9ee4 100644 --- a/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs +++ b/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs @@ -118,12 +118,13 @@ IAsyncEnumerable> GetFilesFilteredAsync(IEnumerable fileIds, FilterTy /// /// /// + /// /// list of files /// /// Return only the latest versions of files of a folder /// IAsyncEnumerable> GetFilesAsync(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, string[] extension, - bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, T roomId = default, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT); + bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, T roomId = default, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT, FormsItemDto formsItemDto = null); /// /// Get stream of file @@ -346,7 +347,8 @@ IAsyncEnumerable> GetFilesAsync(IEnumerable parentIds, FilterType fil Task SaveProperties(T fileId, EntryProperties entryProperties); Task GetFilesCountAsync(T parentId, FilterType filterType, bool subjectGroup, Guid subjectId, string searchText, string[] extension, bool searchInContent, - bool withSubfolders = false, bool excludeSubject = false, T roomId = default); + bool withSubfolders = false, bool excludeSubject = false, T roomId = default, + FormsItemDto formsItemDto = null); Task SetCustomOrder(T fileId, T parentFolderId, int order); diff --git a/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs index 7e8fe21d87..dbb28908a6 100644 --- a/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs @@ -32,6 +32,7 @@ namespace ASC.Files.Core.Data; internal class FileDao( ILogger logger, FactoryIndexerFile factoryIndexer, + FactoryIndexerForm factoryIndexerFormData, UserManager userManager, FileUtility fileUtility, IDbContextFactory dbContextManager, @@ -192,13 +193,14 @@ public async IAsyncEnumerable> GetFilesFilteredAsync(IEnumerable var func = GetFuncForSearch(null, null, filterType, subjectGroup, subjectID, searchText, e, searchInContent); (success, var result) = await factoryIndexer.TrySelectIdsAsync(s => func(s).In(r => r.Id, fileIds.ToArray())); + if(!success) { break; } searchIds = searchIds.Concat(result).ToList(); } - + if (success) { query = query.Where(r => searchIds.Contains(r.Id)); @@ -267,7 +269,7 @@ public async IAsyncEnumerable GetFilesAsync(int parentId) } public async IAsyncEnumerable> GetFilesAsync(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, string[] extension, - bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, int roomId = 0, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT) + bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, int roomId = 0, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT, FormsItemDto formsItemDto = null) { if (filterType == FilterType.FoldersOnly || count == 0) { @@ -276,7 +278,7 @@ public async IAsyncEnumerable> GetFilesAsync(int parentId, OrderBy ord await using var filesDbContext = await _dbContextFactory.CreateDbContextAsync(); - var q = await GetFilesQueryWithFilters(parentId, orderBy, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders, excludeSubject, roomId, extension, filesDbContext); + var q = await GetFilesQueryWithFilters(parentId, orderBy, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders, excludeSubject, roomId, extension, filesDbContext, formsItemDto); if (containingMyFiles) { @@ -478,52 +480,52 @@ public async Task> SaveFileAsync(File file, Stream fileStream, bo } } - var isNew = false; - DbFile toInsert = null; + var isNew = false; + DbFile toInsert = null; var cloneStreamForSave = new MemoryStream(); var streamChange = false; - await using (var filesDbContext = await _dbContextFactory.CreateDbContextAsync()) - { + await using (var filesDbContext = await _dbContextFactory.CreateDbContextAsync()) + { var parentFolders = await filesDbContext.DbFolderTreesAsync(file.ParentId).ToListAsync(); - var parentFoldersIds = parentFolders.Select(r => r.ParentId).ToList(); - - await using (await _distributedLockProvider.TryAcquireFairLockAsync(LockKey)) + var parentFoldersIds = parentFolders.Select(r => r.ParentId).ToList(); + + await using (await _distributedLockProvider.TryAcquireFairLockAsync(LockKey)) + { + var strategy = filesDbContext.Database.CreateExecutionStrategy(); + await strategy.ExecuteAsync(async () => { - var strategy = filesDbContext.Database.CreateExecutionStrategy(); - await strategy.ExecuteAsync(async () => - { - await using var tx = await filesDbContext.Database.BeginTransactionAsync(); + await using var tx = await filesDbContext.Database.BeginTransactionAsync(); if (file.Id == 0) - { - file.Id = await filesDbContext.FileMaxIdAsync() + 1; - file.Version = 1; - file.VersionGroup = 1; - isNew = true; - } + { + file.Id = await filesDbContext.FileMaxIdAsync() + 1; + file.Version = 1; + file.VersionGroup = 1; + isNew = true; + } - file.Title = Global.ReplaceInvalidCharsAndTruncate(file.Title); - //make lowerCase - file.Title = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetFileExtension(file.Title)); + 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(); - + file.ModifiedBy = _authContext.CurrentAccount.ID; + file.ModifiedOn = _tenantUtil.DateTimeNow(); + if (file.CreateBy == Guid.Empty) - { - file.CreateBy = _authContext.CurrentAccount.ID; - } + { + file.CreateBy = _authContext.CurrentAccount.ID; + } - if (file.CreateOn == default) - { - file.CreateOn = _tenantUtil.DateTimeNow(); - } + if (file.CreateOn == default) + { + file.CreateOn = _tenantUtil.DateTimeNow(); + } - if (!isNew) - { - await filesDbContext.DisableCurrentVersionAsync(tenantId, file.Id); - } + if (!isNew) + { + await filesDbContext.DisableCurrentVersionAsync(tenantId, file.Id); + } var fileType = FileUtility.GetFileTypeByFileName(file.Title); @@ -558,7 +560,7 @@ await strategy.ExecuteAsync(async () => ParentId = file.ParentId, Title = file.Title, ContentLength = file.ContentLength, - Category = file.Category != (int)FilterType.None ? file.Category : (int)file.FilterType, + Category = file.Category != (int)FilterType.None ? file.Category : (int)file.FilterType, CreateBy = file.CreateBy, CreateOn = _tenantUtil.DateTimeToUtc(file.CreateOn), ModifiedBy = file.ModifiedBy, @@ -581,42 +583,42 @@ await strategy.ExecuteAsync(async () => } await filesDbContext.SaveChangesAsync(); await tx.CommitAsync(); - }); + }); - file.PureTitle = file.Title; - file.RootCreateBy = currentFolder.RootCreateBy; - file.RootFolderType = currentFolder.RootFolderType; + file.PureTitle = file.Title; + file.RootCreateBy = currentFolder.RootCreateBy; + file.RootFolderType = currentFolder.RootFolderType; - if (parentFoldersIds.Count > 0) - { + if (parentFoldersIds.Count > 0) + { await filesDbContext.UpdateFoldersAsync(parentFoldersIds, _tenantUtil.DateTimeToUtc(file.ModifiedOn), file.ModifiedBy, tenantId); - } - - toInsert.Folders = parentFolders; - - if (isNew) - { - file.Order = await SetCustomOrder(filesDbContext, file.Id, file.ParentId); - } } + toInsert.Folders = parentFolders; + if (isNew) { - await IncrementCountAsync(filesDbContext, file.ParentId, tenantId, FileEntryType.File); - - if (roomId != -1 && checkFolder) + file.Order = await SetCustomOrder(filesDbContext, file.Id, file.ParentId); + } + } + + if (isNew) + { + await IncrementCountAsync(filesDbContext, file.ParentId, tenantId, FileEntryType.File); + + if (roomId != -1 && checkFolder) + { + var currentRoom = await folderDao.GetFolderAsync(roomId); + if (currentRoom.FolderType == FolderType.FillingFormsRoom) { - var currentRoom = await folderDao.GetFolderAsync(roomId); - if (currentRoom.FolderType == FolderType.FillingFormsRoom) - { - var fileProp = await fileDao.GetProperties(file.Id); - var extension = FileUtility.GetFileExtension(file.Title); + var fileProp = await fileDao.GetProperties(file.Id); + var extension = FileUtility.GetFileExtension(file.Title); - if (file.IsForm || (extension == ".csv" && fileProp != null && Equals(fileProp.FormFilling.ResultsFolderId, file.ParentId))) + if (file.IsForm || (extension == ".csv" && fileProp != null && Equals(fileProp.FormFilling.ResultsFolderId, file.ParentId))) + { + var properties = fileProp ?? new EntryProperties { FormFilling = new FormFillingProperties() }; + if (!properties.FormFilling.CollectFillForm) { - var properties = fileProp ?? new EntryProperties { FormFilling = new FormFillingProperties() }; - if (!properties.FormFilling.CollectFillForm) - { var inProcessFormFolder = await folderDao.GetFoldersAsync(currentRoom.Id, FolderType.InProcessFormFolder).FirstOrDefaultAsync(); var readyFormFolder = await folderDao.GetFoldersAsync(currentRoom.Id, FolderType.ReadyFormFolder).FirstOrDefaultAsync(); @@ -637,55 +639,55 @@ await folderDao.GetFolderAsync(inProcessFormFolderId) await filesMessageService.SendAsync(MessageAction.FolderCreated, formFolder, formFolder.Title); } } - properties.FormFilling.StartFilling = true; - properties.FormFilling.CollectFillForm = true; - properties.FormFilling.OriginalFormId = file.Id; - await fileDao.SaveProperties(file.Id, properties); - var count = await fileStorageService.GetPureSharesCountAsync(currentRoom.Id, FileEntryType.Folder, ShareFilterType.UserOrGroup, ""); - if (file.IsForm) - { - await socketManager.CreateFormAsync(file, securityContext.CurrentAccount.ID, count <= 1); - } - } + properties.FormFilling.StartFilling = true; + properties.FormFilling.CollectFillForm = true; + properties.FormFilling.OriginalFormId = file.Id; + await fileDao.SaveProperties(file.Id, properties); + var count = await fileStorageService.GetPureSharesCountAsync(currentRoom.Id, FileEntryType.Folder, ShareFilterType.UserOrGroup, ""); + if (file.IsForm) + { + await socketManager.CreateFormAsync(file, securityContext.CurrentAccount.ID, count <= 1); + } } - else - { + } + else + { var stored = await (await globalStore.GetStoreAsync()).IsDirectoryAsync(GetUniqFileDirectory(file.Id)); await DeleteFileAsync(file.Id, stored, file.GetFileQuotaOwner()); - throw new Exception(FilesCommonResource.ErrorMessage_UploadToFormRoom); - } + throw new Exception(FilesCommonResource.ErrorMessage_UploadToFormRoom); } } - } + } + } } if (fileStream != null) - { + { try { - await SaveFileStreamAsync(file, streamChange ? cloneStreamForSave : fileStream, currentFolder); - } - catch (Exception saveException) + await SaveFileStreamAsync(file, streamChange ? cloneStreamForSave : fileStream, currentFolder); + } + catch (Exception saveException) + { + try { - try + if (isNew) { - if (isNew) - { - var stored = await (await globalStore.GetStoreAsync()).IsDirectoryAsync(GetUniqFileDirectory(file.Id)); - await DeleteFileAsync(file.Id, stored, file.GetFileQuotaOwner()); - } - else if (!await IsExistOnStorageAsync(file)) - { - await DeleteVersionAsync(file); - } + var stored = await (await globalStore.GetStoreAsync()).IsDirectoryAsync(GetUniqFileDirectory(file.Id)); + await DeleteFileAsync(file.Id, stored, file.GetFileQuotaOwner()); } - catch (Exception deleteException) + else if (!await IsExistOnStorageAsync(file)) { - throw new Exception(saveException.Message, deleteException); + await DeleteVersionAsync(file); } - throw; } + catch (Exception deleteException) + { + throw new Exception(saveException.Message, deleteException); + } + throw; + } finally { await cloneStreamForSave.DisposeAsync(); @@ -708,7 +710,7 @@ await folderDao.GetFolderAsync(inProcessFormFolderId) } public async Task GetFilesCountAsync(int parentId, FilterType filterType, bool subjectGroup, Guid subjectId, string searchText, string[] extension, bool searchInContent, - bool withSubfolders = false, bool excludeSubject = false, int roomId = 0) + bool withSubfolders = false, bool excludeSubject = false, int roomId = 0, FormsItemDto formsItemDto = null) { if (filterType == FilterType.FoldersOnly) { @@ -717,7 +719,7 @@ public async Task GetFilesCountAsync(int parentId, FilterType filterType, b var filesDbContext = await _dbContextFactory.CreateDbContextAsync(); - return await (await GetFilesQueryWithFilters(parentId, null, filterType, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, excludeSubject, roomId, extension, filesDbContext)) + return await (await GetFilesQueryWithFilters(parentId, null, filterType, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, excludeSubject, roomId, extension, filesDbContext, formsItemDto)) .CountAsync(); } @@ -937,6 +939,7 @@ await strategy.ExecuteAsync(async () => if (toDeleteFile != null) { await factoryIndexer.DeleteAsync(toDeleteFile); + await factoryIndexerFormData.DeleteAsync(r=> r.Where(a => a.Id, toDeleteFile.Id)); } }); } @@ -1107,7 +1110,7 @@ await storageFactory.QuotaUsedDeleteAsync( var id = fileId.ToString(); await filesDbContext.DeleteTagLinksByTypeAsync(tenantId, id, FileEntryType.File, TagType.RecentByLink); - await filesDbContext.DeleteTagsAsync(tenantId); + await filesDbContext.DeleteTagsAsync( tenantId); await filesDbContext.DeleteLinksAsync(tenantId, id, FileEntryType.File); } @@ -1951,6 +1954,16 @@ private Func, Selector> GetFuncForSearch(int? parentId, return result; }; } + private Func, Selector> GetFuncForSearchInFormsData(int parentId, string searchText, FormsItemDto formsItemDto) + { + return s => + { + s.Where(r => r.ParentId, parentId); + s.Nested(a => a.FormsData, b => b.Term(c => c.FormsData.Select(r=> r.Key), char.ToLower(formsItemDto.Key[0]) + formsItemDto.Key[1..]) && b.Term(c => c.FormsData.Select(r=> r.Value), char.ToLower(searchText[0]) + searchText[1..])); + + return s; + }; + } private IQueryable FromQuery(FilesDbContext filesDbContext, IQueryable dbFiles) { @@ -2095,8 +2108,20 @@ protected internal async Task InitDocumentAsync(DbFile dbFile, int? tena return dbFile; } - private async Task> GetFilesQueryWithFilters(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, - bool withSubfolders, bool excludeSubject, int roomId, string[] extension, FilesDbContext filesDbContext) + private async Task> GetFilesQueryWithFilters( + int parentId, + OrderBy orderBy, + FilterType filterType, + bool subjectGroup, + Guid subjectID, + string searchText, + bool searchInContent, + bool withSubfolders, + bool excludeSubject, + int roomId, + string[] extension, + FilesDbContext filesDbContext, + FormsItemDto formsItemDto) { var tenantId = _tenantManager.GetCurrentTenantId(); var q = GetFileQuery(filesDbContext, r => r.ParentId == parentId && r.CurrentVersion); @@ -2121,9 +2146,10 @@ private async Task> GetFilesQueryWithFilters(int parentId, Or { var searchIds = new List(); var success = false; + foreach (var e in extension) { - var func = GetFuncForSearch(null, null, filterType, subjectGroup, subjectID, searchText, e, searchInContent); + var func = GetFuncForSearch(parentId, null, filterType, subjectGroup, subjectID, searchText, e, searchInContent); Expression, Selector>> expression = s => func(s); @@ -2135,6 +2161,18 @@ private async Task> GetFilesQueryWithFilters(int parentId, Or searchIds = searchIds.Concat(result).ToList(); } + if (searchInContent && formsItemDto != null) + { + var funcForSearchInFormsData = GetFuncForSearchInFormsData(parentId, searchText, formsItemDto); + Expression, Selector>> expressionSearchText = s => funcForSearchInFormsData(s); + + (success, var resultForm) = await factoryIndexerFormData.TrySelectIdsAsync(expressionSearchText); + if (success) + { + searchIds = searchIds.Intersect(resultForm).ToList(); + } + } + if (success) { q = q.Where(r => searchIds.Contains(r.Id)); diff --git a/products/ASC.Files/Core/Core/EF/DbFile.cs b/products/ASC.Files/Core/Core/EF/DbFile.cs index b5918ffc2b..fec350a111 100644 --- a/products/ASC.Files/Core/Core/EF/DbFile.cs +++ b/products/ASC.Files/Core/Core/EF/DbFile.cs @@ -72,7 +72,6 @@ public class DbFile : BaseEntity, IDbFile, IDbSearch, ISearchItemDocument [Ignore] public string IndexName => Tables.File; - public Document Document { get; set; } public Expression> GetSearchContentFields(SearchSettingsHelper searchSettings) diff --git a/products/ASC.Files/Core/Core/Entries/SubmitFormsData.cs b/products/ASC.Files/Core/Core/Entries/SubmitFormsData.cs index 8267916690..b43aa14e36 100644 --- a/products/ASC.Files/Core/Core/Entries/SubmitFormsData.cs +++ b/products/ASC.Files/Core/Core/Entries/SubmitFormsData.cs @@ -25,8 +25,10 @@ // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode namespace ASC.Files.Core; + public class SubmitFormsData { + [Nested] public IEnumerable FormsData { get; set; } } @@ -34,6 +36,83 @@ public class FormsItemData { public string Key { get; set; } public string Tag { get; set; } - public object Value { get; set; } + public string Value { get; set; } public string Type { get; set; } +} + +[Transient] +public class DbFormsItemDataSearch : SubmitFormsData, ISearchItem +{ + public int Id { get; set; } + public int TenantId { get; set; } + public int ParentId { get; set; } + public DateTime CreateOn { get; set; } + + [OpenSearch.Client.Ignore] + public string IndexName => "forms_data"; + + public Expression> GetSearchContentFields(SearchSettingsHelper searchSettings) + { + return a => new object[] { }; + } +} + +[Scope] +public class BaseIndexerForm(Client client, + ILogger log, + IDbContextFactory dbContextManager, + TenantManager tenantManager, + BaseIndexerHelper baseIndexerHelper, + Settings settings, + IServiceProvider serviceProvider) + : BaseIndexer(client, log, dbContextManager, tenantManager, baseIndexerHelper, settings, serviceProvider); + +[Scope(typeof(IFactoryIndexer))] +public class FactoryIndexerForm( + ILoggerProvider options, + TenantManager tenantManager, + SearchSettingsHelper searchSettingsHelper, + FactoryIndexer factoryIndexer, + BaseIndexerForm baseIndexer, + IServiceProvider serviceProvider, + ICache cache) + : FactoryIndexer(options, tenantManager, searchSettingsHelper, factoryIndexer, baseIndexer, serviceProvider, cache) +{ + public override async Task IndexAllAsync() + { + try + { + var now = DateTime.UtcNow; + + await foreach (var _ in _indexer.IndexAllAsync(GetCount, GetIds, GetData)) + { + + } + + await _indexer.OnComplete(now); + } + catch (Exception e) + { + Logger.ErrorFactoryIndexerFile(e); + throw; + } + + return; + + List GetIds(DateTime lastIndexed) + { + return []; + } + + List GetData(long start, long stop, DateTime lastIndexed) + { + return []; + + } + + (int, int, int) GetCount(DateTime lastIndexed) + { + return new(0, 0, 0); + } + } } \ No newline at end of file diff --git a/products/ASC.Files/Core/Core/FileStorageService.cs b/products/ASC.Files/Core/Core/FileStorageService.cs index 43249ef886..602d11f358 100644 --- a/products/ASC.Files/Core/Core/FileStorageService.cs +++ b/products/ASC.Files/Core/Core/FileStorageService.cs @@ -178,7 +178,8 @@ public async Task> GetFolderItemsAsync( SubjectFilter subjectFilter = SubjectFilter.Owner, ApplyFilterOption applyFilterOption = ApplyFilterOption.All, QuotaFilter quotaFilter = QuotaFilter.All, - StorageFilter storageFilter = StorageFilter.None) + StorageFilter storageFilter = StorageFilter.None, + FormsItemDto formsItemDto = null) { var subjectId = string.IsNullOrEmpty(subject) ? Guid.Empty : new Guid(subject); @@ -287,7 +288,8 @@ await folderDao.GetFirstParentTypeFromFileEntryAsync(parent) : subjectFilter, applyFilterOption, quotaFilter, - storageFilter); + storageFilter, + formsItemDto); } catch (Exception e) { diff --git a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index 6b32789302..067d37242f 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -152,12 +152,12 @@ public async IAsyncEnumerable GetFilesAsync(string parentId) } public async IAsyncEnumerable> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, - string[] extension, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, string roomId = null, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT) + string[] extension, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, string roomId = null, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT, FormsItemDto formsItemDto = null) { var selector = _selectorFactory.GetSelector(parentId); var fileDao = selector.GetFileDao(parentId); - var files = fileDao.GetFilesAsync(selector.ConvertId(parentId), orderBy, filterType, subjectGroup, subjectID, searchText, extension, searchInContent, withSubfolders, excludeSubject); + var files = fileDao.GetFilesAsync(selector.ConvertId(parentId), orderBy, filterType, subjectGroup, subjectID, searchText, extension, searchInContent, withSubfolders, excludeSubject, formsItemDto: formsItemDto); var result = await files.Where(r => r != null).ToListAsync(); foreach (var r in result) diff --git a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs index 9137c5cc22..da41263ae7 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -171,7 +171,7 @@ public async IAsyncEnumerable GetFilesAsync(string parentId) } public async IAsyncEnumerable> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, - string[] extension, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, string roomId = null, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT) + string[] extension, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, string roomId = null, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT, FormsItemDto formsItemDto = null) { if (filterType == FilterType.FoldersOnly) { diff --git a/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyFileDao.cs index febffd1495..f28ed23dac 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyFileDao.cs @@ -190,7 +190,7 @@ public async IAsyncEnumerable GetFilesAsync(string parentId) } public async IAsyncEnumerable> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, - string[] extension, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, string roomId = null, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT) + string[] extension, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, int offset = 0, int count = -1, string roomId = null, bool withShared = false, bool containingMyFiles = false, FolderType parentType = FolderType.DEFAULT, FormsItemDto formsItemDto = null) { if (filterType == FilterType.FoldersOnly) { @@ -741,7 +741,7 @@ public Task GetPreSignedUriAsync(File file, TimeSpan expires, st } public Task GetFilesCountAsync(string parentId, FilterType filterType, bool subjectGroup, Guid subjectId, string searchText, string[] extension, bool searchInContent, bool withSubfolders = false, - bool excludeSubject = false, string roomId = null) + bool excludeSubject = false, string roomId = null, FormsItemDto formsItemDto = null) { throw new NotImplementedException(); } diff --git a/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyProviderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyProviderDao.cs index 89f26b704a..ae1a852f19 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyProviderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ThirdPartyProviderDao.cs @@ -97,7 +97,7 @@ public Task> GetProperties(string fileId) { return Task.FromResult>(null); } - + public Task>> GetPropertiesAsync(IEnumerable filesIds) { return Task.FromResult>>(null); @@ -214,7 +214,7 @@ public Task GetFilesUsedSpace() throw new NotImplementedException(); } public Task GetFilesCountAsync(string parentId, FilterType filterType, bool subjectGroup, Guid subjectId, string searchText, string[] extension, bool searchInContent, bool withSubfolders = false, - bool excludeSubject = false, string roomId = null) + bool excludeSubject = false, string roomId = null, FormsItemDto formsItemDto = null) { throw new NotImplementedException(); } diff --git a/products/ASC.Files/Core/Helpers/FormFillingReportCreator.cs b/products/ASC.Files/Core/Helpers/FormFillingReportCreator.cs index b7fdff1165..a6fd024722 100644 --- a/products/ASC.Files/Core/Helpers/FormFillingReportCreator.cs +++ b/products/ASC.Files/Core/Helpers/FormFillingReportCreator.cs @@ -32,7 +32,11 @@ public class FormFillingReportCreator( IDaoFactory daoFactory, IHttpClientFactory clientFactory, TenantUtil tenantUtil, - TenantManager tenantManager) + TenantManager tenantManager, + FactoryIndexerForm factoryIndexerForm, + CommonLinkUtility commonLinkUtility, + FilesLinkUtility filesLinkUtility, + FileUtility fileUtility) { private static readonly JsonSerializerOptions _options = new() { @@ -40,27 +44,46 @@ public class FormFillingReportCreator( PropertyNameCaseInsensitive = true }; - public async Task UpdateFormFillingReport(T resultsFileId, int resultFormNumber, string formsDataUrl, string resultUrl) + public async Task UpdateFormFillingReport(T resultsFileId, int resultFormNumber, string formsDataUrl, File formsDataFile) { - if (formsDataUrl != null) { var fileDao = daoFactory.GetFileDao(); - var submitFormsData = await GetSubmitFormsData(resultFormNumber, formsDataUrl, resultUrl); + var submitFormsData = await GetSubmitFormsData(formsDataFile, resultFormNumber, formsDataUrl); if (resultsFileId != null) { var resultsFile = await fileDao.GetFileAsync(resultsFileId); - - var updateDt = exportToCSV.CreateDataTable(submitFormsData.FormsData); - await exportToCSV.UpdateCsvReport(resultsFile, updateDt); - + + await exportToCSV.UpdateCsvReport(resultsFile, submitFormsData.FormsData); } } } - private async Task GetSubmitFormsData(int resultFormNumber, string url, string resultUrl) + public async Task> GetFormsFields(int folderId) { + var folderDao = daoFactory.GetFolderDao(); + var folder = await folderDao.GetFolderAsync(folderId); + if (folder?.FolderType != FolderType.FormFillingFolderDone) + { + return []; + } + + var fileDao = daoFactory.GetFileDao(); + var file = await fileDao.GetFilesAsync([folderId], FilterType.Pdf, false, Guid.Empty, null, null, false).FirstOrDefaultAsync(); + var (success, result) = await factoryIndexerForm.TrySelectAsync(r => r.Where(s => s.Id, file.Id)); + + if (success) + { + return result.SelectMany(r => r.FormsData); + } + + return []; + } + + private async Task GetSubmitFormsData(File formsDataFile, int resultFormNumber, string url) + { + var resultUrl = commonLinkUtility.GetFullAbsolutePath(filesLinkUtility.GetFileWebPreviewUrl(fileUtility, formsDataFile.Title, formsDataFile.Id, formsDataFile.Version)); var request = new HttpRequestMessage { RequestUri = new Uri(url), @@ -76,25 +99,38 @@ private async Task GetSubmitFormsData(int resultFormNumber, str new() { Key = FilesCommonResource.ResourceManager.GetString("FormNumber", tenantCulture), - Value = resultFormNumber + Value = resultFormNumber.ToString() } }; - - var formLink = new FormsItemData + List formInfo = + [ + new() { Key = FilesCommonResource.ResourceManager.GetString("Date", tenantCulture), Value = $"=\"{tenantUtil.DateTimeNow().ToString("G", tenantCulture)}\"" }, + new() { Key = FilesCommonResource.ResourceManager.GetString("LinkToForm", tenantCulture), Value = $"=HYPERLINK(\"{resultUrl}\";\"{FilesCommonResource.ResourceManager.GetString("OpenForm", tenantCulture)}\")" } + ]; + + var fromData = JsonSerializer.Deserialize(data, _options); + var result = new SubmitFormsData { - Key = FilesCommonResource.ResourceManager.GetString("LinkToForm", tenantCulture), - Value = $"=HYPERLINK(\"{resultUrl}\";\"{FilesCommonResource.ResourceManager.GetString("OpenForm", tenantCulture)}\")" + FormsData = formNumber.Concat(fromData.FormsData).ToList() }; - var date = new FormsItemData + result.FormsData = result.FormsData.Concat(formInfo).ToList(); + + var now = DateTime.UtcNow; + var tenantId = tenantManager.GetCurrentTenantId(); + + if (formsDataFile.Id is int id && formsDataFile.ParentId is int parentId) { - Key = FilesCommonResource.ResourceManager.GetString("Date", tenantCulture), - Value = $"=\"{tenantUtil.DateTimeNow().ToString("G", tenantCulture)}\"" - }; - var result = JsonSerializer.Deserialize(data, _options); + var searchItems = new DbFormsItemDataSearch + { + Id = id, + TenantId = tenantId, + ParentId = parentId, + CreateOn = now, + FormsData = fromData.FormsData + }; - result.FormsData = formNumber.Concat(result.FormsData); - result.FormsData = result.FormsData.Append(date); - result.FormsData = result.FormsData.Append(formLink); + await factoryIndexerForm.IndexAsync(searchItems); + } return result; } diff --git a/products/ASC.Files/Core/Utils/EntryManager.cs b/products/ASC.Files/Core/Utils/EntryManager.cs index 4fa0d8cfd8..9112353ea3 100644 --- a/products/ASC.Files/Core/Utils/EntryManager.cs +++ b/products/ASC.Files/Core/Utils/EntryManager.cs @@ -56,7 +56,7 @@ public async Task GetBreadCrumbsOrderAsync(T folderId) var result = breadcrumbs.Skip(2).Select(r => r.Order.ToString()).ToList(); return result.Count != 0 ? result.Aggregate((first, second) => $"{first}.{second}") : null; - } + } public async Task> GetBreadCrumbsAsync(T folderId) { @@ -208,7 +208,7 @@ public async Task SetFormInfoAsync(IEnumerable> files) if (!files.Any()) { return; - } +} var pdfs = new List>(); @@ -283,7 +283,6 @@ public class EntryManager(IDaoFactory daoFactory, SocketManager socketManager, FilesMessageService filesMessageService, BaseCommonLinkUtility commonLinkUtility, - FilesLinkUtility filesLinkUtility, SecurityContext securityContext, FormFillingReportCreator formFillingReportCreator, TenantUtil tenantUtil, @@ -321,7 +320,8 @@ public class EntryManager(IDaoFactory daoFactory, SubjectFilter subjectFilter = SubjectFilter.Owner, ApplyFilterOption applyFilterOption = ApplyFilterOption.All, QuotaFilter quotaFilter = QuotaFilter.All, - StorageFilter storageFilter = StorageFilter.None) + StorageFilter storageFilter = StorageFilter.None, + FormsItemDto formsItemDto = null) { int total; var withShared = false; @@ -454,7 +454,7 @@ public class EntryManager(IDaoFactory daoFactory, var fileDao = daoFactory.GetFileDao(); var allFoldersCountTask = folderDao.GetFoldersCountAsync(parent.Id, foldersFilterType, subjectGroup, subjectId, foldersSearchText, withSubfolders, excludeSubject, roomId); - var allFilesCountTask = fileDao.GetFilesCountAsync(parent.Id, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, searchInContent, withSubfolders, excludeSubject, roomId); + var allFilesCountTask = fileDao.GetFilesCountAsync(parent.Id, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, searchInContent, withSubfolders, excludeSubject, roomId, formsItemDto); var filesToUpdate = new List>(); if (room is { FolderType: FolderType.VirtualDataRoom, SettingsIndexing: true }) @@ -462,7 +462,7 @@ public class EntryManager(IDaoFactory daoFactory, orderBy.SortedBy = SortedByType.CustomOrder; var folders = folderDao.GetFoldersAsync(parent.Id, orderBy, foldersFilterType, subjectGroup, subjectId, foldersSearchText, withSubfolders, excludeSubject, 0, -1, roomId); - var files = fileDao.GetFilesAsync(parent.Id, orderBy, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, searchInContent, withSubfolders, excludeSubject, 0, -1, roomId, withShared); + var files = fileDao.GetFilesAsync(parent.Id, orderBy, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, searchInContent, withSubfolders, excludeSubject, 0, -1, roomId, withShared, formsItemDto: formsItemDto); var temp = files.Concat(folders.Cast()) .OrderBy(r => r.Order) @@ -488,7 +488,7 @@ public class EntryManager(IDaoFactory daoFactory, containingMyFiles = true; } } - + var foldersTask = folderDao.GetFoldersAsync(parent.Id, orderBy, foldersFilterType, subjectGroup, subjectId, foldersSearchText, withSubfolders, excludeSubject, from, count, roomId, containingMyFiles, parent.FolderType); @@ -510,10 +510,10 @@ public class EntryManager(IDaoFactory daoFactory, var filesCount = count - folders.Count; var filesOffset = Math.Max(folders.Count > 0 ? 0 : from - await allFoldersCountTask, 0); - - var filesTask = fileDao.GetFilesAsync(parent.Id, orderBy, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, - searchInContent, withSubfolders, excludeSubject, filesOffset, filesCount, roomId, withShared, containingMyFiles && withSubfolders, parent.FolderType); + var filesTask = fileDao.GetFilesAsync(parent.Id, orderBy, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, searchInContent, withSubfolders, + excludeSubject, filesOffset, filesCount, roomId, withShared, containingMyFiles && withSubfolders, parent.FolderType, formsItemDto); + if (parent.RootFolderType is FolderType.VirtualRooms or FolderType.Archive) { filesTask = filesTask.Select(x => @@ -522,7 +522,7 @@ public class EntryManager(IDaoFactory daoFactory, return x; }); } - + var files = await filesTask.ToListAsync(); if (parent.FolderType == FolderType.FillingFormsRoom && securityContext.CurrentAccount.ID.Equals(ASC.Core.Configuration.Constants.Guest.ID)) @@ -574,10 +574,10 @@ public class EntryManager(IDaoFactory daoFactory, { var folders = daoFactory.GetFolderDao().GetFoldersAsync(parent.Id, orderBy, foldersFilterType, subjectGroup, subjectId, foldersSearchText, withSubfolders, excludeSubject); var files = daoFactory.GetFileDao().GetFilesAsync(parent.Id, orderBy, filesFilterType, subjectGroup, subjectId, filesSearchText, fileExtension, searchInContent, withSubfolders, excludeSubject, withShared: withShared); - + var task1 = fileSecurity.FilterReadAsync(folders).ToListAsync(); var task2 = fileSecurity.FilterReadAsync(files).ToListAsync(); - + if (filterType is FilterType.None or FilterType.FoldersOnly) { var folderList = GetThirdPartyFoldersAsync(parent, searchText); @@ -1542,13 +1542,13 @@ public async Task> SaveEditingAsync(T fileId, string fileExtension, s var originalForm = await fileDao.GetFileAsync(originalFormId); await using (await distributedLockProvider.TryAcquireFairLockAsync($"fillform_{roomId}_{originalFormId}")) - { + { var origProperties = await daoFactory.GetFileDao().GetProperties(originalFormId); if (userId.Equals(ASC.Core.Configuration.Constants.Guest.ID) && (origProperties.FormFilling.ResultsFileID == null || Equals(origProperties.FormFilling.ResultsFileID, default(T)))) - { + { await InitFormFillingFolders(file, room, origProperties, folderDao, fileDao, originalForm.CreateBy); origProperties = await daoFactory.GetFileDao().GetProperties(originalFormId); - } + } origProperties.FormFilling.ResultFormNumber++; await fileDao.SaveProperties(originalFormId, origProperties); @@ -1586,12 +1586,12 @@ public async Task> SaveEditingAsync(T fileId, string fileExtension, s File result; if (tmpStream.CanSeek) - { + { pdfFile.ContentLength = tmpStream.Length; result = await fileDao.SaveFileAsync(pdfFile, tmpStream, false); - } - else - { + } + else + { var (buffered, isNew) = await tempStream.TryGetBufferedAsync(tmpStream); try { @@ -1609,7 +1609,7 @@ public async Task> SaveEditingAsync(T fileId, string fileExtension, s await notifyClient.SendFormSubmittedAsync(room, originalForm, pdfFile); if (fillingSessionId != null) - { + { await distributedCache.SetStringAsync(fillingSessionId, result.Id.ToString()); } @@ -1631,7 +1631,7 @@ public async Task> SaveEditingAsync(T fileId, string fileExtension, s ResultsFileID = origProperties.FormFilling.ResultsFileID, ResultFormNumber = origProperties.FormFilling.ResultFormNumber } - }; + }; await fileDao.SaveProperties(result.Id, resProp); var aces = await fileSharing.GetSharedInfoAsync(room); @@ -1639,9 +1639,8 @@ public async Task> SaveEditingAsync(T fileId, string fileExtension, s await fileMarker.MarkAsNewAsync(result, users.Where(x => x != userId).ToList()); await socketManager.CreateFileAsync(result, users); - - var resultUrl = commonLinkUtility.GetFullAbsolutePath(filesLinkUtility.GetFileWebPreviewUrl(fileUtility, result.Title, result.Id, result.Version)); - await formFillingReportCreator.UpdateFormFillingReport(origProperties.FormFilling.ResultsFileID, resProp.FormFilling.ResultFormNumber, formsDataUrl, resultUrl); + + await formFillingReportCreator.UpdateFormFillingReport(origProperties.FormFilling.ResultsFileID, resProp.FormFilling.ResultFormNumber, formsDataUrl, result); if (!securityContext.CurrentAccount.ID.Equals(ASC.Core.Configuration.Constants.Guest.ID)) { @@ -1653,8 +1652,8 @@ public async Task> SaveEditingAsync(T fileId, string fileExtension, s await fileMarker.RemoveMarkAsNewForAllAsync(file); await linkDao.DeleteAllLinkAsync(file.Id); + } } - } catch(Exception ex) { logger.LogError(ex, "Form submission error"); @@ -1894,10 +1893,10 @@ async Task CopyThumbnailsAsync() var dao = scope.ServiceProvider.GetService().GetFileDao(); var globalStoreLocal = scope.ServiceProvider.GetService(); - foreach (var size in thumbnailSettings.Sizes) - { + foreach (var size in thumbnailSettings.Sizes) + { await (await globalStoreLocal.GetStoreAsync()).CopyAsync(String.Empty, dao.GetUniqThumbnailPath(file, size.Width, size.Height), String.Empty, dao.GetUniqThumbnailPath(newFile, size.Width, size.Height)); - } + } await dao.SetThumbnailStatusAsync(newFile, Thumbnail.Created); } @@ -2065,8 +2064,8 @@ public async Task MarkFileAsRecentByLink(File file, Guid linkId) { var marked = await fileMarker.MarkAsRecentByLink(file, linkId); if (marked == MarkResult.Marked) - { - file.FolderIdDisplay = await globalFolderHelper.GetFolderRecentAsync(); + { + file.FolderIdDisplay = await globalFolderHelper.GetFolderRecentAsync(); await socketManager.CreateFileAsync(file, [authContext.CurrentAccount.ID]); } } @@ -2153,15 +2152,15 @@ private async Task CreateFormFillingFolder(string sourceTitle, T parentId, private async Task CreateCsvResult(T resultsFolderId, Guid createBy, string sourceTitle, IFileDao fileDao) { using var textStream = new MemoryStream(Encoding.UTF8.GetBytes("")); - var csvFile = serviceProvider.GetService>(); - csvFile.ParentId = resultsFolderId; - csvFile.Title = Global.ReplaceInvalidCharsAndTruncate(sourceTitle + ".csv"); - csvFile.CreateBy = createBy; + var csvFile = serviceProvider.GetService>(); + csvFile.ParentId = resultsFolderId; + csvFile.Title = Global.ReplaceInvalidCharsAndTruncate(sourceTitle + ".csv"); + csvFile.CreateBy = createBy; - var file = await fileDao.SaveFileAsync(csvFile, textStream, false); + var file = await fileDao.SaveFileAsync(csvFile, textStream, false); - return file.Id; - } + return file.Id; + } private async Task> InitFormFillingProperties(T roomId, string sourceTitle, T sourceFileId, T inProcessFormFolderId, T readyFormFolderId, Guid createBy, EntryProperties properties, IFileDao fileDao, IFolderDao folderDao) { @@ -2185,7 +2184,7 @@ private async Task> InitFormFillingProperties(T roomId, st await fileDao.SaveProperties(sourceFileId, properties); return properties; - } + } private async Task SetOriginsAsync(Folder parent, IEnumerable entries) { diff --git a/products/ASC.Files/Core/Utils/ExportToCSV.cs b/products/ASC.Files/Core/Utils/ExportToCSV.cs index 99073911df..1576424315 100644 --- a/products/ASC.Files/Core/Utils/ExportToCSV.cs +++ b/products/ASC.Files/Core/Utils/ExportToCSV.cs @@ -55,10 +55,11 @@ public async Task UploadCsvReport(T parentId, string title, DataTable data } } - public async Task UpdateCsvReport(File file, DataTable dataTable) + public async Task UpdateCsvReport(File file, IEnumerable list) { try - { + { + var dataTable = CreateDataTable(list); var fileDao = daoFactory.GetFileDao(); await using var source = await fileDao.GetFileStreamAsync(file); @@ -82,7 +83,7 @@ public async Task UpdateCsvReport(File file, DataTable dataTable) } } - public DataTable CreateDataTable(IEnumerable list) + private DataTable CreateDataTable(IEnumerable list) { var dataTable = new DataTable(); dataTable.TableName = typeof(FormsItemData).FullName; diff --git a/products/ASC.Files/Server/Api/FoldersController.cs b/products/ASC.Files/Server/Api/FoldersController.cs index 9abbe0b79d..0ec658acfd 100644 --- a/products/ASC.Files/Server/Api/FoldersController.cs +++ b/products/ASC.Files/Server/Api/FoldersController.cs @@ -37,8 +37,10 @@ public class FoldersControllerInternal( FileDtoHelper fileDtoHelper, PermissionContext permissionContext, FileShareDtoHelper fileShareDtoHelper, - HistoryApiHelper historyApiHelper) - : FoldersController(breadCrumbsManager, + HistoryApiHelper historyApiHelper, + FormFillingReportCreator formFillingReportCreator) + : FoldersController( + breadCrumbsManager, folderContentDtoHelper, fileStorageService, fileOperationsManager, @@ -65,6 +67,13 @@ public IAsyncEnumerable GetHistoryAsync(HistoryFolderRequestDto inDt { return historyApiHelper.GetFolderHistoryAsync(inDto.FolderId, inDto.FromDate, inDto.ToDate); } + + [AllowAnonymous] + [HttpGet("{folderId:int}/formfilter")] + public async Task> GetFolderAsync(int folderId) + { + return (await formFillingReportCreator.GetFormsFields(folderId)).Select(r => new FormsItemDto(r.Key, r.Type)); + } } public class FoldersControllerThirdparty( @@ -162,8 +171,13 @@ public async Task> GetFolderAsync(GetFolderRequestDto inD { var split = inDto.Extension == null ? [] : inDto.Extension.Split(","); - var folder = await folderContentDtoHelper.GetAsync(inDto.FolderId, inDto.UserIdOrGroupId, inDto.FilterType, inDto.RoomId, inDto.SearchInContent, inDto.Withsubfolders, inDto.ExcludeSubject, inDto.ApplyFilterOption, inDto.SearchArea, split); - + FormsItemDto formsItemDto = null; + if (!string.IsNullOrEmpty(inDto.FormsItemKey) || !string.IsNullOrEmpty(inDto.FormsItemType)) + { + formsItemDto = new FormsItemDto(inDto.FormsItemKey, inDto.FormsItemType); + } + + var folder = await folderContentDtoHelper.GetAsync(inDto.FolderId, inDto.UserIdOrGroupId, inDto.FilterType, inDto.RoomId, inDto.SearchInContent, inDto.Withsubfolders, inDto.ExcludeSubject, inDto.ApplyFilterOption, inDto.SearchArea, split, formsItemDto); return folder.NotFoundIfNull(); } @@ -273,7 +287,7 @@ public async Task GetFilesUsedSpace() return await fileStorageService.GetFilesUsedSpace(); } - + /// /// Returns the primary external link by the identifier specified in the request. ///