Files: added origin in trash for files

This commit is contained in:
Maksim Chegulov 2023-02-06 18:35:07 +03:00
parent dbb81e3752
commit 1d6192d067
13 changed files with 399 additions and 301 deletions

View File

@ -24,32 +24,33 @@
// 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
#nullable enable
using static ASC.Files.Core.Security.FileSecurity;
namespace ASC.Files.Core.ApiModels.ResponseDto;
public abstract class FileEntryDto
{
protected internal abstract FileEntryType EntryType { get; }
public string Title { get; set; }
public FileShare Access { get; set; }
public bool Shared { get; set; }
public ApiDateTime Created { get; set; }
public string Title { get; set; }
public FileShare Access { get; set; }
public bool Shared { get; set; }
public ApiDateTime Created { get; set; }
public EmployeeDto CreatedBy { get; set; }
private ApiDateTime _updated;
private ApiDateTime _updated;
public ApiDateTime Updated
{
get => _updated < Created ? Created : _updated;
set => _updated = value;
}
public FolderType RootFolderType { get; set; }
public EmployeeDto UpdatedBy { get; set; }
public bool? ProviderItem { get; set; }
public string ProviderKey { get; set; }
public FolderType RootFolderType { get; set; }
public EmployeeDto UpdatedBy { get; set; }
public bool? ProviderItem { get; set; }
public string ProviderKey { get; set; }
public int? ProviderId { get; set; }
protected FileEntryDto(FileEntry entry)
{
Title = entry.Title;
@ -60,24 +61,32 @@ public abstract class FileEntryDto
ProviderKey = entry.ProviderKey;
ProviderId = entry.ProviderId.NullIfDefault();
}
protected FileEntryDto() { }
}
public abstract class FileEntryDto<T> : FileEntryDto
{
{
public T Id { get; set; }
public T RootFolderId { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public T OriginId { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public T OriginRoomId { get; set; }
public string OriginTitle { get; set; }
public string OriginRoomTitle { get; set; }
public bool CanShare { get; set; }
public IDictionary<FilesSecurityActions, bool> Security { get; set; }
protected FileEntryDto(FileEntry<T> entry)
: base(entry)
{
Id = entry.Id;
RootFolderId = entry.RootId;
}
protected FileEntryDto() { }
}
@ -129,7 +138,11 @@ public class FileEntryDtoHelper
ProviderKey = entry.ProviderKey,
ProviderId = entry.ProviderId.NullIfDefault(),
CanShare = await _fileSharingHelper.CanSetAccessAsync(entry),
Security = entry.Security
Security = entry.Security,
OriginId = entry.OriginId,
OriginTitle = entry.OriginTitle,
OriginRoomId = entry.OriginRoomId,
OriginRoomTitle = entry.OriginRoomTitle
};
}
}
}

View File

@ -29,249 +29,249 @@ namespace ASC.Files.Core;
[Scope]
public interface IFileDao<T>
{
/// <summary>
/// Clear the application cache for the specific file
/// <summary>
/// Clear the application cache for the specific file
/// </summary>
Task InvalidateCacheAsync(T fileId);
/// <summary>
/// Receive file
/// </summary>
/// <param name="fileId">file id</param>
/// <summary>
/// Receive file
/// </summary>
/// <param name="fileId">file id</param>
/// <returns></returns>
Task<File<T>> GetFileAsync(T fileId);
/// <summary>
/// Receive file
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion">file version</param>
/// <summary>
/// Receive file
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion">file version</param>
/// <returns></returns>
Task<File<T>> GetFileAsync(T fileId, int fileVersion);
/// <summary>
/// Receive file
/// </summary>
/// <param name="parentId">folder id</param>
/// <param name="title">file name</param>
/// <returns>
/// file
/// <summary>
/// Receive file
/// </summary>
/// <param name="parentId">folder id</param>
/// <param name="title">file name</param>
/// <returns>
/// file
/// </returns>
Task<File<T>> GetFileAsync(T parentId, string title);
/// <summary>
/// Receive last file without forcesave
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion"></param>
/// <returns></returns>
/// <summary>
/// Receive last file without forcesave
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion"></param>
/// <returns></returns>
Task<File<T>> GetFileStableAsync(T fileId, int fileVersion = -1);
/// <summary>
/// Returns all versions of the file
/// </summary>
/// <param name="fileId"></param>
/// <summary>
/// Returns all versions of the file
/// </summary>
/// <param name="fileId"></param>
/// <returns></returns>
IAsyncEnumerable<File<T>> GetFileHistoryAsync(T fileId);
/// <summary>
/// Gets the file (s) by ID (s)
/// </summary>
/// <param name="fileIds">id file</param>
/// <summary>
/// Gets the file (s) by ID (s)
/// </summary>
/// <param name="fileIds">id file</param>
/// <returns></returns>
IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> fileIds);
/// <summary>
/// Gets the file (s) by ID (s) for share
/// </summary>
/// <param name="fileIds">id file</param>
/// <param name="filterType"></param>
/// <param name="subjectGroup"></param>
/// <param name="subjectID"></param>
/// <param name="searchText"></param>
/// <param name="searchInContent"></param>
/// <returns></returns>
/// <summary>
/// Gets the file (s) by ID (s) for share
/// </summary>
/// <param name="fileIds">id file</param>
/// <param name="filterType"></param>
/// <param name="subjectGroup"></param>
/// <param name="subjectID"></param>
/// <param name="searchText"></param>
/// <param name="searchInContent"></param>
/// <returns></returns>
IAsyncEnumerable<File<T>> GetFilesFilteredAsync(IEnumerable<T> fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool checkShared = false);
/// <summary>
///
/// </summary>
/// <param name="parentId"></param>
/// <summary>
///
/// </summary>
/// <param name="parentId"></param>
/// <returns></returns>
IAsyncEnumerable<T> GetFilesAsync(T parentId);
/// <summary>
/// Get files in folder
/// </summary>
/// <param name="parentId">folder id</param>
/// <param name="orderBy"></param>
/// <param name="filterType">filterType type</param>
/// <param name="subjectGroup"></param>
/// <param name="subjectID"></param>
/// <param name="searchText"> </param>
/// <param name="searchInContent"></param>
/// <param name="withSubfolders"> </param>
/// <returns>list of files</returns>
/// <remarks>
/// Return only the latest versions of files of a folder
/// <summary>
/// Get files in folder
/// </summary>
/// <param name="parentId">folder id</param>
/// <param name="orderBy"></param>
/// <param name="filterType">filterType type</param>
/// <param name="subjectGroup"></param>
/// <param name="subjectID"></param>
/// <param name="searchText"> </param>
/// <param name="searchInContent"></param>
/// <param name="withSubfolders"> </param>
/// <returns>list of files</returns>
/// <remarks>
/// Return only the latest versions of files of a folder
/// </remarks>
IAsyncEnumerable<File<T>> GetFilesAsync(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool exludeSubject = false);
IAsyncEnumerable<File<T>> GetFilesAsync(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool exludeSubject = false, bool withOrigin = false);
/// <summary>
/// Get stream of file
/// </summary>
/// <param name="file"></param>
/// <summary>
/// Get stream of file
/// </summary>
/// <param name="file"></param>
/// <returns>Stream</returns>
Task<Stream> GetFileStreamAsync(File<T> file);
/// <summary>
/// Get stream of file
/// </summary>
/// <param name="file"></param>
/// <param name="offset"></param>
/// <summary>
/// Get stream of file
/// </summary>
/// <param name="file"></param>
/// <param name="offset"></param>
/// <returns>Stream</returns>
Task<Stream> GetFileStreamAsync(File<T> file, long offset);
/// <summary>
/// Get presigned uri
/// </summary>
/// <param name="file"></param>
/// <param name="expires"></param>
/// <summary>
/// Get presigned uri
/// </summary>
/// <param name="file"></param>
/// <param name="expires"></param>
/// <returns>Stream uri</returns>
Task<Uri> GetPreSignedUriAsync(File<T> file, TimeSpan expires);
/// <summary>
/// Check is supported PreSignedUri
/// </summary>
/// <param name="file"></param>
/// <summary>
/// Check is supported PreSignedUri
/// </summary>
/// <param name="file"></param>
/// <returns>Stream uri</returns>
Task<bool> IsSupportedPreSignedUriAsync(File<T> file);
/// <summary>
/// Saves / updates the version of the file
/// and save stream of file
/// </summary>
/// <param name="file"></param>
/// <param name="fileStream"> </param>
/// <returns></returns>
/// <remarks>
/// Updates the file if:
/// - The file comes with the given id
/// - The file with that name in the folder / container exists
///
/// Save in all other cases
/// </remarks>
/// <summary>
/// Saves / updates the version of the file
/// and save stream of file
/// </summary>
/// <param name="file"></param>
/// <param name="fileStream"> </param>
/// <returns></returns>
/// <remarks>
/// Updates the file if:
/// - The file comes with the given id
/// - The file with that name in the folder / container exists
///
/// Save in all other cases
/// </remarks>
Task<File<T>> SaveFileAsync(File<T> file, Stream fileStream);
/// <summary>
///
/// </summary>
/// <param name="file"></param>
/// <param name="fileStream"></param>
/// <returns></returns>
/// <summary>
///
/// </summary>
/// <param name="file"></param>
/// <param name="fileStream"></param>
/// <returns></returns>
Task<File<T>> ReplaceFileVersionAsync(File<T> file, Stream fileStream);
/// <summary>
/// Deletes a file including all previous versions
/// </summary>
/// <param name="fileId">file id</param>
/// <summary>
/// Deletes a file including all previous versions
/// </summary>
/// <param name="fileId">file id</param>
Task DeleteFileAsync(T fileId);
/// <summary>
/// Checks whether or not file
/// </summary>
/// <param name="title">file name</param>
/// <param name="folderId">folder id</param>
/// <returns>Returns true if the file exists, otherwise false</returns>
/// <summary>
/// Checks whether or not file
/// </summary>
/// <param name="title">file name</param>
/// <param name="folderId">folder id</param>
/// <returns>Returns true if the file exists, otherwise false</returns>
Task<bool> IsExistAsync(string title, object folderId);
/// <summary>
/// Moves a file or set of files in a folder
/// </summary>
/// <param name="fileId">file id</param>
/// <summary>
/// Moves a file or set of files in a folder
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="toFolderId">The ID of the destination folder</param>
Task<T> MoveFileAsync(T fileId, T toFolderId);
Task<TTo> MoveFileAsync<TTo>(T fileId, TTo toFolderId);
Task<string> MoveFileAsync(T fileId, string toFolderId);
Task<int> MoveFileAsync(T fileId, int toFolderId);
/// <summary>
/// Copy the files in a folder
/// </summary>
/// <param name="fileId">file id</param>
/// <summary>
/// Copy the files in a folder
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="toFolderId">The ID of the destination folder</param>
Task<File<T>> CopyFileAsync(T fileId, T toFolderId);
Task<File<TTo>> CopyFileAsync<TTo>(T fileId, TTo toFolderId);
Task<File<string>> CopyFileAsync(T fileId, string toFolderId);
Task<File<int>> CopyFileAsync(T fileId, int toFolderId);
/// <summary>
/// Rename file
/// </summary>
/// <param name="file"></param>
/// <summary>
/// Rename file
/// </summary>
/// <param name="file"></param>
/// <param name="newTitle">new name</param>
Task<T> FileRenameAsync(File<T> file, string newTitle);
/// <summary>
/// Update comment file
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion">file version</param>
/// <param name="comment">new comment</param>
/// <summary>
/// Update comment file
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion">file version</param>
/// <param name="comment">new comment</param>
Task<string> UpdateCommentAsync(T fileId, int fileVersion, string comment);
/// <summary>
/// Complete file version
/// </summary>
/// <param name="fileId">file id</param>
/// <summary>
/// Complete file version
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion">file version</param>
Task CompleteVersionAsync(T fileId, int fileVersion);
/// <summary>
/// Continue file version
/// </summary>
/// <param name="fileId">file id</param>
/// <summary>
/// Continue file version
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="fileVersion">file version</param>
Task ContinueVersionAsync(T fileId, int fileVersion);
/// <summary>
/// Check the need to use the trash before removing
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
/// <summary>
/// Check the need to use the trash before removing
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
bool UseTrashForRemove(File<T> file);
string GetUniqFilePath(File<T> file, string fileTitle);
#region chunking
#region chunking
Task<ChunkedUploadSession<T>> CreateUploadSessionAsync(File<T> file, long contentLength);
Task<File<T>> UploadChunkAsync(ChunkedUploadSession<T> uploadSession, Stream chunkStream, long chunkLength);
Task AbortUploadSessionAsync(ChunkedUploadSession<T> uploadSession);
#endregion
#endregion
#region Only in TMFileDao
#region Only in TMFileDao
/// <summary>
/// Set created by
/// </summary>
/// <param name="fileIds"></param>
/// <summary>
/// Set created by
/// </summary>
/// <param name="fileIds"></param>
/// <param name="newOwnerId"></param>
Task ReassignFilesAsync(T[] fileIds, Guid newOwnerId);
/// <summary>
/// Search files in SharedWithMe & Projects
/// </summary>
/// <param name="parentIds"></param>
/// <param name="filterType"></param>
/// <param name="subjectGroup"></param>
/// <param name="subjectID"></param>
/// <param name="searchText"></param>
/// <param name="searchInContent"></param>
/// <summary>
/// Search files in SharedWithMe & Projects
/// </summary>
/// <param name="parentIds"></param>
/// <param name="filterType"></param>
/// <param name="subjectGroup"></param>
/// <param name="subjectID"></param>
/// <param name="searchText"></param>
/// <param name="searchInContent"></param>
/// <returns></returns>
IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);
/// <summary>
/// Search the list of files containing text
/// Only in TMFileDao
/// </summary>
/// <param name="text">search text</param>
/// <param name="bunch"></param>
/// <returns>list of files</returns>
/// <summary>
/// Search the list of files containing text
/// Only in TMFileDao
/// </summary>
/// <param name="text">search text</param>
/// <param name="bunch"></param>
/// <returns>list of files</returns>
IAsyncEnumerable<File<T>> SearchAsync(string text, bool bunch = false);
/// <summary>
/// Checks whether file exists on storage
/// </summary>
/// <param name="file">file</param>
/// <returns></returns>
/// <summary>
/// Checks whether file exists on storage
/// </summary>
/// <param name="file">file</param>
/// <returns></returns>
Task<bool> IsExistOnStorageAsync(File<T> file);
@ -289,15 +289,15 @@ public interface IFileDao<T>
Task<Stream> GetThumbnailAsync(File<T> file, int width, int height);
Task<Stream> GetThumbnailAsync(T fileId, int width, int height);
Task<Stream> GetThumbnailAsync(T fileId, int width, int height);
IAsyncEnumerable<FileWithShare> GetFeedsAsync(int tenant, DateTime from, DateTime to);
IAsyncEnumerable<int> GetTenantsWithFeedsAsync(DateTime fromTime, bool includeSecurity);
Task<EntryProperties> GetProperties(T fileId);
Task SaveProperties(T fileId, EntryProperties entryProperties);
#endregion
Task<EntryProperties> GetProperties(T fileId);
Task SaveProperties(T fileId, EntryProperties entryProperties);
#endregion
}

View File

@ -24,8 +24,6 @@
// 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.OneDrive.Sdk;
using Document = ASC.ElasticSearch.Document;
namespace ASC.Files.Core.Data;
@ -48,6 +46,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
private readonly IMapper _mapper;
private readonly ThumbnailSettings _thumbnailSettings;
private readonly IQuotaService _quotaService;
private readonly TagDao<int> _tagDao;
public FileDao(
ILogger<FileDao> logger,
@ -75,7 +74,8 @@ internal class FileDao : AbstractDao, IFileDao<int>
Settings settings,
IMapper mapper,
ThumbnailSettings thumbnailSettings,
IQuotaService quotaService)
IQuotaService quotaService,
TagDao<int> tagDao)
: base(
dbContextManager,
userManager,
@ -104,6 +104,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
_mapper = mapper;
_thumbnailSettings = thumbnailSettings;
_quotaService = quotaService;
_tagDao = tagDao;
}
public Task InvalidateCacheAsync(int fileId)
@ -278,7 +279,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
}
}
public async IAsyncEnumerable<File<int>> GetFilesAsync(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false)
public async IAsyncEnumerable<File<int>> GetFilesAsync(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, bool withOrigin = false)
{
if (filterType == FilterType.FoldersOnly)
{
@ -360,7 +361,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
break;
}
await foreach (var e in FromQuery(filesDbContext, q).AsAsyncEnumerable())
await foreach (var e in (withOrigin ? FromQueryWithOrigin(filesDbContext, q) : FromQuery(filesDbContext, q)).AsAsyncEnumerable())
{
yield return _mapper.Map<DbFileQuery, File<int>>(e);
}
@ -892,11 +893,13 @@ internal class FileDao : AbstractDao, IFileDao<int>
using (var tx = await filesDbContext.Database.BeginTransactionAsync())
{
var trashId = await trashIdTask;
var oldParentId = toUpdate.FirstOrDefault()?.ParentId;
foreach (var f in toUpdate)
{
f.ParentId = toFolderId;
var trashId = await trashIdTask;
if (trashId.Equals(toFolderId))
{
f.ModifiedBy = _authContext.CurrentAccount.ID;
@ -904,6 +907,16 @@ internal class FileDao : AbstractDao, IFileDao<int>
}
}
if (toFolderId == trashId && oldParentId.HasValue)
{
var origin = Tag.Origin(fileId, FileEntryType.File, oldParentId.Value, _authContext.CurrentAccount.ID);
await _tagDao.SaveTags(origin);
}
else if (oldParentId == trashId)
{
await _tagDao.RemoveTagLinksAsync(fileId, FileEntryType.File, TagType.Origin);
}
await filesDbContext.SaveChangesAsync();
await tx.CommitAsync();
@ -1701,6 +1714,39 @@ internal class FileDao : AbstractDao, IFileDao<int>
});
}
private IQueryable<DbFileQuery> FromQueryWithOrigin(FilesDbContext filesDbContext, IQueryable<DbFile> dbFiles)
{
return dbFiles
.Select(r => new DbFileQuery
{
File = r,
Root = (from f in filesDbContext.Folders
where f.Id ==
(from t in filesDbContext.Tree
where t.FolderId == r.ParentId
orderby t.Level descending
select t.ParentId
).FirstOrDefault()
where f.TenantId == r.TenantId
select f
).FirstOrDefault(),
Origin = filesDbContext.Folders.AsNoTracking()
.FirstOrDefault(f => f.TenantId == TenantID && f.Id.ToString() == filesDbContext.TagLink.AsNoTracking()
.Where(l => l.TenantId == TenantID && Convert.ToInt32(l.EntryId) == r.Id && l.EntryType == FileEntryType.File)
.Join(filesDbContext.Tag.AsNoTracking(), l => l.TagId, t => t.Id, (l, t) => t.Name)
.FirstOrDefault()),
OriginRoom = filesDbContext.Folders.AsNoTracking()
.FirstOrDefault(f => f.TenantId == TenantID && f.Id == filesDbContext.Tree.AsNoTracking()
.Where(tree => tree.FolderId.ToString() == filesDbContext.TagLink.AsNoTracking()
.Where(l => l.TenantId == TenantID && Convert.ToInt32(l.EntryId) == r.Id && l.EntryType == FileEntryType.File)
.Join(filesDbContext.Tag.AsNoTracking(), l => l.TagId, t => t.Id, (l, t) => t.Name)
.FirstOrDefault())
.OrderByDescending(tree => tree.Level).Skip(1)
.Select(t => t.ParentId)
.FirstOrDefault())
});
}
protected internal Task<DbFile> InitDocumentAsync(DbFile dbFile)
{
if (!_factoryIndexer.CanIndexByContent(dbFile))
@ -1749,7 +1795,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
}
}
public class DbFileQuery
public class DbFileQuery : OriginQuery
{
public DbFile File { get; set; }
public DbFolder Root { get; set; }

View File

@ -112,6 +112,10 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
{
public T Id { get; set; }
public T ParentId { get; set; }
public T OriginId { get; set; }
public T OriginRoomId { get; set; }
public string OriginTitle { get; set; }
public string OriginRoomTitle { get; set; }
public IDictionary<FilesSecurityActions, bool> Security { get; set; }
@ -193,4 +197,4 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
{
return Title;
}
}
}

View File

@ -0,0 +1,33 @@
// (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.Files.Core;
public abstract class OriginQuery
{
public DbFolder OriginRoom { get; set; }
public DbFolder Origin { get; set; }
}

View File

@ -186,7 +186,7 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
}
}
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false)
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, bool withOrigin = false)
{
if (filterType == FilterType.FoldersOnly)
{
@ -575,7 +575,7 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
return ProviderInfo.GetThumbnailAsync(boxFileId, width, height);
}
#region chunking
#region chunking
private File<string> RestoreIds(File<string> file)
{
@ -659,5 +659,5 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
return Task.CompletedTask;
}
#endregion
}
#endregion
}

View File

@ -189,7 +189,7 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
}
}
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false)
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, bool withOrigin = false)
{
if (filterType == FilterType.FoldersOnly)
{
@ -574,7 +574,7 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId), width, height);
}
#region chunking
#region chunking
private File<string> RestoreIds(File<string> file)
{
@ -707,5 +707,5 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
return Task.CompletedTask;
}
#endregion
}
#endregion
}

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
using DriveFile = Google.Apis.Drive.v3.Data.File;
using DriveFile = Google.Apis.Drive.v3.Data.File;
using File = System.IO.File;
namespace ASC.Files.Thirdparty.GoogleDrive;
@ -188,7 +188,7 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
}
}
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false)
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, bool withOrigin = false)
{
if (filterType == FilterType.FoldersOnly)
{
@ -578,7 +578,7 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId)), width, height);
}
#region chunking
#region chunking
private File<string> RestoreIds(File<string> file)
{
@ -733,5 +733,5 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
return Task.CompletedTask;
}
#endregion
}
#endregion
}

View File

@ -187,7 +187,7 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao<string>
}
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool excludeSubject = false, bool withoutMe = false)
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool excludeSubject = false, bool withoutMe = false, bool withOrigin = false)
{
if (filterType == FilterType.FoldersOnly)
{
@ -585,7 +585,7 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao<string>
return ProviderInfo.GetThumbnailAsync(oneDriveId, width, height);
}
#region chunking
#region chunking
private File<string> RestoreIds(File<string> file)
{
@ -730,5 +730,5 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao<string>
System.IO.File.Delete(uploadSession.GetItemOrDefault<string>("TempPath"));
}
}
#endregion
}
#endregion
}

View File

@ -162,7 +162,7 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
}
}
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false)
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, bool withOrigin = false)
{
var selector = GetSelector(parentId);
@ -181,12 +181,12 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
return GetFileStreamAsync(file, 0);
}
/// <summary>
/// Get stream of file
/// </summary>
/// <param name="file"></param>
/// <param name="offset"></param>
/// <returns>Stream</returns>
/// <summary>
/// Get stream of file
/// </summary>
/// <param name="file"></param>
/// <param name="offset"></param>
/// <returns>Stream</returns>
public Task<Stream> GetFileStreamAsync(File<string> file, long offset)
{
ArgumentNullException.ThrowIfNull(file);
@ -442,10 +442,10 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
var selector = GetSelector(file.Id);
var fileDao = selector.GetFileDao(file.Id);
return fileDao.UseTrashForRemove(file);
return fileDao.UseTrashForRemove(file);
}
#region chunking
#region chunking
public Task<ChunkedUploadSession<string>> CreateUploadSessionAsync(File<string> file, long contentLength)
{
@ -512,5 +512,5 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
return fileDao.GetThumbnailAsync(file, width, height);
}
#endregion
}
#endregion
}

View File

@ -177,7 +177,7 @@ internal class SharePointFileDao : SharePointDaoBase, IFileDao<string>
}
}
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false)
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, bool withOrigin = false)
{
if (filterType == FilterType.FoldersOnly)
{

View File

@ -172,7 +172,7 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao<string>
}
}
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false)
public async IAsyncEnumerable<File<string>> GetFilesAsync(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false, bool excludeSubject = false, bool withOrigin = false)
{
if (filterType == FilterType.FoldersOnly)
{
@ -586,7 +586,7 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao<string>
return false;
}
#region chunking
#region chunking
public async Task<ChunkedUploadSession<string>> CreateUploadSessionAsync(File<string> file, long contentLength)
{
@ -731,5 +731,5 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao<string>
return file;
}
#endregion
}
#endregion
}

View File

@ -32,43 +32,43 @@ public class LockerManager
private readonly AuthContext _authContext;
private readonly IDaoFactory _daoFactory;
private readonly ThirdPartySelector _thirdPartySelector;
public LockerManager(AuthContext authContext, IDaoFactory daoFactory, ThirdPartySelector thirdPartySelector)
public LockerManager(AuthContext authContext, IDaoFactory daoFactory, ThirdPartySelector thirdPartySelector)
{
_authContext = authContext;
_daoFactory = daoFactory;
_thirdPartySelector = thirdPartySelector;
}
public async Task<bool> FileLockedForMe<T>(T fileId, Guid userId = default)
{
var app = _thirdPartySelector.GetAppByFileId(fileId.ToString());
var app = _thirdPartySelector.GetAppByFileId(fileId.ToString());
if (app != null)
{
return false;
}
userId = userId == default ? _authContext.CurrentAccount.ID : userId;
var tagDao = _daoFactory.GetTagDao<T>();
var lockedBy = await FileLockedBy(fileId, tagDao);
return lockedBy != Guid.Empty && lockedBy != userId;
}
public async Task<bool> FileLockedForMeAsync<T>(T fileId, Guid userId = default)
{
var app = _thirdPartySelector.GetAppByFileId(fileId.ToString());
var app = _thirdPartySelector.GetAppByFileId(fileId.ToString());
if (app != null)
{
return false;
}
userId = userId == default ? _authContext.CurrentAccount.ID : userId;
var tagDao = _daoFactory.GetTagDao<T>();
var lockedBy = await FileLockedByAsync(fileId, tagDao);
return lockedBy != Guid.Empty && lockedBy != userId;
}
public async Task<Guid> FileLockedBy<T>(T fileId, ITagDao<T> tagDao)
{
var tagLock = await tagDao.GetTagsAsync(fileId, FileEntryType.File, TagType.Locked).FirstOrDefaultAsync();
@ -82,7 +82,7 @@ public class LockerManager
var tagLock = await tags.FirstOrDefaultAsync();
return tagLock != null ? tagLock.Owner : Guid.Empty;
}
}
}
[Scope]
@ -92,7 +92,7 @@ public class BreadCrumbsManager
private readonly FileSecurity _fileSecurity;
private readonly GlobalFolderHelper _globalFolderHelper;
private readonly AuthContext _authContext;
public BreadCrumbsManager(
IDaoFactory daoFactory,
FileSecurity fileSecurity,
@ -104,24 +104,24 @@ public class BreadCrumbsManager
_globalFolderHelper = globalFolderHelper;
_authContext = authContext;
}
public Task<List<FileEntry>> GetBreadCrumbsAsync<T>(T folderId)
{
var folderDao = _daoFactory.GetFolderDao<T>();
return GetBreadCrumbsAsync(folderId, folderDao);
}
public async Task<List<FileEntry>> GetBreadCrumbsAsync<T>(T folderId, IFolderDao<T> folderDao)
{
if (folderId == null)
{
return new List<FileEntry>();
}
var breadCrumbs = await _fileSecurity.FilterReadAsync(folderDao.GetParentFoldersAsync(folderId)).Cast<FileEntry>().ToListAsync();
var breadCrumbs = await _fileSecurity.FilterReadAsync(folderDao.GetParentFoldersAsync(folderId)).Cast<FileEntry>().ToListAsync();
var firstVisible = breadCrumbs.ElementAtOrDefault(0) as Folder<T>;
var rootId = 0;
if (firstVisible == null)
{
@ -151,7 +151,7 @@ public class BreadCrumbsManager
}
}
break;
case FolderType.BUNCH:
rootId = await _globalFolderHelper.FolderProjectsAsync;
break;
@ -173,12 +173,12 @@ public class BreadCrumbsManager
}
var folderDaoInt = _daoFactory.GetFolderDao<int>();
if (rootId != 0)
{
breadCrumbs.Insert(0, await folderDaoInt.GetFolderAsync(rootId));
}
return breadCrumbs;
}
}
@ -203,7 +203,7 @@ public class EntryStatusManager
{
return;
}
await SetFileStatusAsync(new List<File<T>>(1) { file });
}
@ -221,7 +221,7 @@ public class EntryStatusManager
var tags = await tagsTask;
var tagsNew = await tagsNewTask;
foreach (var file in files)
{
if (tags.TryGetValue(file.Id, out var lockedTag))
@ -234,7 +234,7 @@ public class EntryStatusManager
continue;
}
if (tagsNew.Any(r => r.EntryId.Equals(file.Id)))
{
file.IsNew = true;
@ -307,7 +307,7 @@ public class EntryManager
private readonly FilesMessageService _filesMessageService;
private readonly DisplayUserSettingsHelper _displayUserSettingsHelper;
private readonly SocketManager _socketManager;
public EntryManager(
IDaoFactory daoFactory,
FileSecurity fileSecurity,
@ -332,8 +332,8 @@ public class EntryManager
ICache cache,
FileTrackerHelper fileTracker,
EntryStatusManager entryStatusManager,
ThirdPartySelector thirdPartySelector,
IHttpClientFactory clientFactory,
ThirdPartySelector thirdPartySelector,
IHttpClientFactory clientFactory,
FilesMessageService filesMessageService,
ThumbnailSettings thumbnailSettings,
DisplayUserSettingsHelper displayUserSettingsHelper,
@ -369,18 +369,19 @@ public class EntryManager
_displayUserSettingsHelper = displayUserSettingsHelper;
_socketManager = socketManager;
}
public async Task<(IEnumerable<FileEntry> Entries, int Total)> GetEntriesAsync<T>(Folder<T> parent, int from, int count, FilterType filterType, bool subjectGroup, Guid subjectId,
string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy, SearchArea searchArea = SearchArea.Active, bool withoutTags = false, IEnumerable<string> tagNames = null,
bool excludeSubject = false, ProviderFilter provider = ProviderFilter.None, SubjectFilter subjectFilter = SubjectFilter.Owner)
{
{
var total = 0;
var withOrigin = false;
if (parent == null)
{
throw new ArgumentNullException(nameof(parent), FilesCommonResource.ErrorMassage_FolderNotFound);
}
if (parent.ProviderEntry && !_filesSettingsHelper.EnableThirdParty)
{
throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFolder);
@ -392,9 +393,9 @@ public class EntryManager
}
var entries = new List<FileEntry>();
searchInContent = searchInContent && filterType != FilterType.ByExtension && !Equals(parent.Id, _globalFolderHelper.FolderTrash);
if (parent.FolderType == FolderType.Projects && parent.Id.Equals(await _globalFolderHelper.FolderProjectsAsync))
{
@ -403,7 +404,7 @@ public class EntryManager
{
//share
var shared = await _fileSecurity.GetSharesForMeAsync(filterType, subjectGroup, subjectId, searchText, searchInContent, withSubfolders).ToListAsync();
entries.AddRange(shared);
CalculateTotal();
@ -464,17 +465,18 @@ public class EntryManager
if (parent.FolderType == FolderType.TRASH)
{
withSubfolders = false;
withOrigin = true;
}
var folders = _daoFactory.GetFolderDao<T>().GetFoldersAsync(parent.Id, orderBy, filterType, subjectGroup, subjectId, searchText, withSubfolders, excludeSubject);
var files = _daoFactory.GetFileDao<T>().GetFilesAsync(parent.Id, orderBy, filterType, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, excludeSubject);
var files = _daoFactory.GetFileDao<T>().GetFilesAsync(parent.Id, orderBy, filterType, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, excludeSubject, withOrigin);
var task1 = _fileSecurity.FilterReadAsync(folders).ToListAsync();
var task2 = _fileSecurity.FilterReadAsync(files).ToListAsync();
if (filterType == FilterType.None || filterType == FilterType.FoldersOnly)
{
var folderList = GetThirpartyFoldersAsync(parent, searchText);
var folderList = GetThirpartyFoldersAsync(parent, searchText);
var thirdPartyFolder = FilterEntries(folderList, filterType, subjectGroup, subjectId, searchText, searchInContent);
var task3 = thirdPartyFolder.ToListAsync();
@ -496,9 +498,9 @@ public class EntryManager
}
total = entries.Count;
IEnumerable<FileEntry> data = entries;
if (orderBy.SortedBy != SortedByType.New)
{
if (parent.FolderType != FolderType.Recent)
@ -509,8 +511,8 @@ public class EntryManager
if (0 < from)
{
data = data.Skip(from);
}
}
if (0 < count)
{
data = data.Take(count);
@ -518,7 +520,7 @@ public class EntryManager
data = data.ToList();
}
await _fileMarker.SetTagsNewAsync(parent, data);
//sorting after marking
@ -529,8 +531,8 @@ public class EntryManager
if (0 < from)
{
data = data.Skip(from);
}
}
if (0 < count)
{
data = data.Take(count);
@ -613,7 +615,7 @@ public class EntryManager
}
public async IAsyncEnumerable<Folder<string>> GetThirpartyFoldersAsync<T>(Folder<T> parent, string searchText = null)
{
{
if ((parent.Id.Equals(_globalFolderHelper.FolderMy) || parent.Id.Equals(await _globalFolderHelper.FolderCommonAsync))
&& _thirdpartyConfiguration.SupportInclusion(_daoFactory)
&& (_filesSettingsHelper.EnableThirdParty
@ -624,7 +626,7 @@ public class EntryManager
{
yield break;
}
var providers = providerDao.GetProvidersInfoAsync(parent.RootFolderType, searchText);
var securityDao = _daoFactory.GetSecurityDao<string>();
@ -646,7 +648,7 @@ public class EntryManager
yield return fake;
}
}
}
}
}
@ -800,7 +802,7 @@ public class EntryManager
{
return entries;
}
if (subjectId != Guid.Empty)
{
entries = entries.Where(f =>
@ -809,9 +811,9 @@ public class EntryManager
: f.CreateBy == subjectId
);
}
Func<FileEntry<T>, bool> where = null;
switch (filter)
{
case FilterType.SpreadsheetsOnly:
@ -833,14 +835,14 @@ public class EntryManager
where = f => !string.IsNullOrEmpty(filterExt) && f.FileEntryType == FileEntryType.File && FileUtility.GetFileExtension(f.Title).Equals(filterExt);
break;
}
if (where != null)
{
entries = entries.Where(where);
}
searchText = (searchText ?? string.Empty).ToLower().Trim();
if ((!searchInContent || filter == FilterType.ByExtension) && !string.IsNullOrEmpty(searchText))
{
entries = entries.Where(f => f.Title.Contains(searchText, StringComparison.InvariantCultureIgnoreCase));
@ -848,7 +850,7 @@ public class EntryManager
return entries;
}
public IEnumerable<FileEntry> SortEntries<T>(IEnumerable<FileEntry> entries, OrderBy orderBy)
{
if (entries == null || !entries.Any())
@ -860,7 +862,7 @@ public class EntryManager
{
orderBy = _filesSettingsHelper.DefaultOrder;
}
var c = orderBy.IsAsc ? 1 : -1;
Comparison<FileEntry> sorter = orderBy.SortedBy switch
{
@ -958,10 +960,10 @@ public class EntryManager
rooms = rooms.OrderBy(r => r, comparer);
folders = folders.OrderBy(r => r, comparer);
files = files.OrderBy(r => r, comparer);
return pinnedRooms.Concat(rooms).Concat(folders).Concat(files);
}
return entries.OrderBy(r => r, comparer);
}
@ -1194,7 +1196,7 @@ public class EntryManager
return false;
}
}
private async Task<bool> SubmitFillFormFromSource<TDraft, TSource>(File<TDraft> draft, TSource sourceId)
{
try
@ -1297,19 +1299,19 @@ public class EntryManager
return false;
}
}
public async Task<File<T>> SaveEditingAsync<T>(T fileId, string fileExtension, string downloadUri, Stream stream, string doc, string comment = null, bool checkRight = true, bool encrypted = false, ForcesaveType? forcesave = null, bool keepLink = false)
{
var newExtension = string.IsNullOrEmpty(fileExtension)
? FileUtility.GetFileExtension(downloadUri)
: fileExtension;
if (!string.IsNullOrEmpty(newExtension))
{
newExtension = "." + newExtension.Trim('.');
}
var app = _thirdPartySelector.GetAppByFileId(fileId.ToString());
if (!string.IsNullOrEmpty(newExtension))
{
newExtension = "." + newExtension.Trim('.');
}
var app = _thirdPartySelector.GetAppByFileId(fileId.ToString());
if (app != null)
{
await app.SaveFileAsync(fileId.ToString(), newExtension, downloadUri, stream);
@ -1509,10 +1511,10 @@ public class EntryManager
throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound);
}
if (!editLink
&& (!await _fileSecurity.CanEditAsync(file, userId)
&& !await _fileSecurity.CanCustomFilterEditAsync(file, userId)
&& !await _fileSecurity.CanReviewAsync(file, userId)
&& !await _fileSecurity.CanFillFormsAsync(file, userId)
&& (!await _fileSecurity.CanEditAsync(file, userId)
&& !await _fileSecurity.CanCustomFilterEditAsync(file, userId)
&& !await _fileSecurity.CanReviewAsync(file, userId)
&& !await _fileSecurity.CanFillFormsAsync(file, userId)
&& !await _fileSecurity.CanCommentAsync(file, userId)))
{
throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile);
@ -1904,4 +1906,4 @@ public class EntryManager
await folderDao.ReassignFoldersAsync(folderIds.ToArray(), toUserId);
}
}
}