Files: ComposeFileOperation

This commit is contained in:
pavelbannov 2020-03-19 15:56:34 +03:00
parent 4a543560a7
commit 50c745dbd0
7 changed files with 162 additions and 120 deletions

View File

@ -81,17 +81,11 @@ namespace ASC.Api.Documents
public FilesControllerHelper<int> FilesControllerHelperInt { get; }
public FileStorageService<int> FileStorageServiceInt { get; }
public GlobalFolderHelper GlobalFolderHelper { get; }
public FileWrapperHelper FileWrapperHelper { get; }
public FilesSettingsHelper FilesSettingsHelper { get; }
public FilesLinkUtility FilesLinkUtility { get; }
public FileUploader FileUploader { get; }
public DocumentServiceHelper DocumentServiceHelper { get; }
public TenantManager TenantManager { get; }
public SecurityContext SecurityContext { get; }
public FolderWrapperHelper FolderWrapperHelper { get; }
public FileOperationWraperHelper FileOperationWraperHelper { get; }
public FileShareWrapperHelper FileShareWrapperHelper { get; }
public FileShareParamsHelper FileShareParamsHelper { get; }
public EntryManager EntryManager { get; }
public UserManager UserManager { get; }
public WebItemSecurity WebItemSecurity { get; }
@ -109,7 +103,6 @@ namespace ASC.Api.Documents
public WordpressHelper WordpressHelper { get; }
public ConsumerFactory ConsumerFactory { get; }
public EasyBibHelper EasyBibHelper { get; }
public ChunkedUploadSessionHelper ChunkedUploadSessionHelper { get; }
public ProductEntryPoint ProductEntryPoint { get; }
/// <summary>
@ -123,17 +116,11 @@ namespace ASC.Api.Documents
FileStorageService<string> fileStorageService,
FileStorageService<int> fileStorageServiceInt,
GlobalFolderHelper globalFolderHelper,
FileWrapperHelper fileWrapperHelper,
FilesSettingsHelper filesSettingsHelper,
FilesLinkUtility filesLinkUtility,
FileUploader fileUploader,
DocumentServiceHelper documentServiceHelper,
TenantManager tenantManager,
SecurityContext securityContext,
FolderWrapperHelper folderWrapperHelper,
FileOperationWraperHelper fileOperationWraperHelper,
FileShareWrapperHelper fileShareWrapperHelper,
FileShareParamsHelper fileShareParamsHelper,
EntryManager entryManager,
UserManager userManager,
WebItemSecurity webItemSecurity,
@ -156,17 +143,11 @@ namespace ASC.Api.Documents
FileStorageService = fileStorageService;
FileStorageServiceInt = fileStorageServiceInt;
GlobalFolderHelper = globalFolderHelper;
FileWrapperHelper = fileWrapperHelper;
FilesSettingsHelper = filesSettingsHelper;
FilesLinkUtility = filesLinkUtility;
FileUploader = fileUploader;
DocumentServiceHelper = documentServiceHelper;
TenantManager = tenantManager;
SecurityContext = securityContext;
FolderWrapperHelper = folderWrapperHelper;
FileOperationWraperHelper = fileOperationWraperHelper;
FileShareWrapperHelper = fileShareWrapperHelper;
FileShareParamsHelper = fileShareParamsHelper;
EntryManager = entryManager;
UserManager = userManager;
WebItemSecurity = webItemSecurity;
@ -184,7 +165,6 @@ namespace ASC.Api.Documents
WordpressToken = wordpressToken;
WordpressHelper = wordpressHelper;
EasyBibHelper = easyBibHelper;
ChunkedUploadSessionHelper = chunkedUploadSessionHelper;
ProductEntryPoint = productEntryPoint;
}
@ -1059,14 +1039,10 @@ namespace ASC.Api.Documents
/// <category>File operations</category>
/// <returns>Operation result</returns>
[Update("fileops/delete")]
public IEnumerable<FileOperationWraper<string>> DeleteBatchItems(DeleteBatchModel<string> batch)
public IEnumerable<FileOperationWraper<object>> DeleteBatchItems(DeleteBatchModel<object> batch)
{
var itemList = new ItemList<string>();
itemList.AddRange((batch.FolderIds ?? new List<string>()).Select(x => "folder_" + x));
itemList.AddRange((batch.FileIds ?? new List<string>()).Select(x => "file_" + x));
return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get<string>);
return FileStorageService.DeleteItems("delete", batch.FileIds.ToList(), batch.FolderIds.ToList(), false, batch.DeleteAfter, batch.Immediately)
.Select(FileOperationWraperHelper.Get<object>);
}
/// <summary>
@ -1076,9 +1052,9 @@ namespace ASC.Api.Documents
/// <category>File operations</category>
/// <returns>Operation result</returns>
[Update("fileops/emptytrash")]
public IEnumerable<FileOperationWraper<string>> EmptyTrash()
public IEnumerable<FileOperationWraper<int>> EmptyTrash()
{
return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get<string>);
return FilesControllerHelperInt.EmptyTrash();
}
/// <summary>
@ -1240,31 +1216,13 @@ namespace ASC.Api.Documents
[Update("{fileId}/sharedlink")]
public string GenerateSharedLink(string fileId, FileShare share)
{
var file = GetFileInfo(fileId);
return FilesControllerHelperString.GenerateSharedLink(fileId, share);
}
var objectId = "file_" + file.Id;
var sharedInfo = FileStorageService.GetSharedInfo(new ItemList<string> { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId);
if (sharedInfo == null || sharedInfo.Share != share)
{
var list = new ItemList<AceWrapper>
{
new AceWrapper
{
SubjectId = FileConstant.ShareLinkId,
SubjectGroup = true,
Share = share
}
};
var aceCollection = new AceCollection
{
Entries = new ItemList<string> { objectId },
Aces = list
};
FileStorageService.SetAceObject(aceCollection, false);
sharedInfo = FileStorageService.GetSharedInfo(new ItemList<string> { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId);
}
return sharedInfo.Link;
[Update("{fileId:int}/sharedlink")]
public string GenerateSharedLink(int fileId, FileShare share)
{
return FilesControllerHelperInt.GenerateSharedLink(fileId, share);
}
/// <summary>
@ -1384,7 +1342,7 @@ namespace ASC.Api.Documents
[Read("thirdparty/common")]
public IEnumerable<Folder<string>> GetCommonThirdPartyFolders()
{
var parent = FileStorageService.GetFolder(GlobalFolderHelper.FolderCommon.ToString());
var parent = FileStorageServiceInt.GetFolder(GlobalFolderHelper.FolderCommon);
return EntryManager.GetThirpartyFolders(parent);
}

View File

@ -1358,6 +1358,11 @@ namespace ASC.Web.Files.Services.WCFService
return FileOperationsManagerHelper.Delete(foldersId, filesId, ignoreException, !deleteAfter, immediately, GetHttpHeaders());
}
public ItemList<FileOperationResult> DeleteItems(string action, List<object> files, List<object> folders, bool ignoreException = false, bool deleteAfter = false, bool immediately = false)
{
return FileOperationsManagerHelper.Delete(folders, files, ignoreException, !deleteAfter, immediately, GetHttpHeaders());
}
public ItemList<FileOperationResult> EmptyTrash()
{
var folderDao = GetFolderDao();

View File

@ -508,9 +508,9 @@ namespace ASC.Files.Helpers
.Select(FileOperationWraperHelper.Get<T>);
}
public IEnumerable<FileOperationWraper<string>> EmptyTrash()
public IEnumerable<FileOperationWraper<int>> EmptyTrash()
{
return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get<string>);
return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get<int>);
}
public IEnumerable<FileWrapper<T>> GetFileVersionInfo(T fileId)

View File

@ -7,10 +7,13 @@ namespace ASC.Files.Model
{
public class BaseBatchModel<T>
{
public IEnumerable<int> FolderIdsInt { get; set; }
public IEnumerable<string> FolderIdsString { get; set; }
public IEnumerable<T> FolderIds { get; set; }
public IEnumerable<T> FileIds { get; set; }
public BaseBatchModel()
{
FolderIds = new List<T>();
FileIds = new List<T>();
}
}
public class DownloadModel<T> : BaseBatchModel<T>

View File

@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ASC.Core.Tenants;
using ASC.Files.Core;
@ -55,6 +56,19 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
}
}
class FileDeleteOperation : ComposeFileOperation<FileDeleteOperationData<string>, FileDeleteOperationData<int>>
{
public FileDeleteOperation(IServiceProvider serviceProvider, FileOperation<FileDeleteOperationData<string>, string> f1, FileOperation<FileDeleteOperationData<int>, int> f2)
: base(serviceProvider, f1, f2)
{
}
public override FileOperationType OperationType
{
get { return FileOperationType.Delete; }
}
}
class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
{
private T _trashId;

View File

@ -48,26 +48,7 @@ using Microsoft.Extensions.Options;
namespace ASC.Web.Files.Services.WCFService.FileOperations
{
abstract class FileOperationData<T>
{
public List<T> Folders { get; private set; }
public List<T> Files { get; private set; }
public Tenant Tenant { get; }
public bool HoldResult { get; private set; }
protected FileOperationData(List<T> folders, List<T> files, Tenant tenant, bool holdResult = true)
{
Folders = folders ?? new List<T>();
Files = files ?? new List<T>();
Tenant = tenant;
HoldResult = holdResult;
}
}
public static class FileOperation
public abstract class FileOperation
{
public const string SPLIT_CHAR = ":";
public const string OWNER = "Owner";
@ -79,23 +60,107 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
public const string PROCESSED = "Processed";
public const string FINISHED = "Finished";
public const string HOLD = "Hold";
}
abstract class FileOperation<T, TId> where T : FileOperationData<TId>
{
private readonly IPrincipal principal;
private readonly string culture;
private int total;
private int processed;
private int successProcessed;
protected readonly IPrincipal principal;
protected readonly string culture;
protected int total;
protected int processed;
protected int successProcessed;
protected DistributedTask TaskInfo { get; private set; }
public virtual FileOperationType OperationType { get; }
public bool HoldResult { get; set; }
protected string Status { get; set; }
protected string Error { get; set; }
protected DistributedTask TaskInfo { get; set; }
public FileOperation(IServiceProvider serviceProvider)
{
principal = serviceProvider.GetService<Microsoft.AspNetCore.Http.IHttpContextAccessor>()?.HttpContext?.User ?? Thread.CurrentPrincipal;
culture = Thread.CurrentThread.CurrentCulture.Name;
TaskInfo = new DistributedTask();
}
public virtual DistributedTask GetDistributedTask()
{
FillDistributedTask();
return TaskInfo;
}
protected internal virtual void FillDistributedTask()
{
var progress = total != 0 ? 100 * processed / total : 0;
TaskInfo.SetProperty(OPERATION_TYPE, OperationType);
TaskInfo.SetProperty(OWNER, ((IAccount)(principal ?? Thread.CurrentPrincipal).Identity).ID);
TaskInfo.SetProperty(PROGRESS, progress < 100 ? progress : 100);
TaskInfo.SetProperty(RESULT, Status);
TaskInfo.SetProperty(ERROR, Error);
TaskInfo.SetProperty(PROCESSED, successProcessed);
TaskInfo.SetProperty(HOLD, HoldResult);
}
public abstract void RunJob(DistributedTask _, CancellationToken cancellationToken);
protected abstract void Do(IServiceScope serviceScope);
}
internal class ComposeFileOperation<T1, T2> : FileOperation
where T1 : FileOperationData<string>
where T2 : FileOperationData<int>
{
public FileOperation<T1, string> F1 { get; set; }
public FileOperation<T2, int> F2 { get; set; }
public ComposeFileOperation(IServiceProvider serviceProvider, FileOperation<T1, string> f1, FileOperation<T2, int> f2)
: base(serviceProvider)
{
F1 = f1;
F2 = f2;
}
public override void RunJob(DistributedTask _, CancellationToken cancellationToken)
{
F1.RunJob(_, cancellationToken);
F2.RunJob(_, cancellationToken);
}
protected internal override void FillDistributedTask()
{
F1.FillDistributedTask();
F2.FillDistributedTask();
}
protected override void Do(IServiceScope serviceScope)
{
throw new NotImplementedException();
}
}
abstract class FileOperationData<T>
{
public List<T> Folders { get; private set; }
public List<T> Files { get; private set; }
public Tenant Tenant { get; }
public bool HoldResult { get; set; }
protected FileOperationData(List<T> folders, List<T> files, Tenant tenant, bool holdResult = true)
{
Folders = folders ?? new List<T>();
Files = files ?? new List<T>();
Tenant = tenant;
HoldResult = holdResult;
}
}
abstract class FileOperation<T, TId> : FileOperation where T : FileOperationData<TId>
{
protected Tenant CurrentTenant { get; private set; }
protected FileSecurity FilesSecurity { get; private set; }
@ -116,17 +181,10 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
protected List<TId> Files { get; private set; }
protected bool HoldResult { get; private set; }
public abstract FileOperationType OperationType { get; }
public IServiceProvider ServiceProvider { get; }
protected FileOperation(IServiceProvider serviceProvider, T fileOperationData)
protected FileOperation(IServiceProvider serviceProvider, T fileOperationData) : base(serviceProvider)
{
principal = Thread.CurrentPrincipal;
culture = Thread.CurrentThread.CurrentCulture.Name;
TaskInfo = new DistributedTask();
ServiceProvider = serviceProvider;
Files = fileOperationData.Files;
Folders = fileOperationData.Folders;
@ -134,7 +192,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
CurrentTenant = fileOperationData.Tenant;
}
public void RunJob(DistributedTask _, CancellationToken cancellationToken)
public override void RunJob(DistributedTask _, CancellationToken cancellationToken)
{
try
{
@ -184,32 +242,18 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
{
try
{
TaskInfo.SetProperty(FileOperation.FINISHED, true);
TaskInfo.SetProperty(FINISHED, true);
PublishTaskInfo();
}
catch { /* ignore */ }
}
}
public virtual DistributedTask GetDistributedTask()
protected internal override void FillDistributedTask()
{
FillDistributedTask();
return TaskInfo;
}
base.FillDistributedTask();
protected virtual void FillDistributedTask()
{
var progress = total != 0 ? 100 * processed / total : 0;
TaskInfo.SetProperty(FileOperation.SOURCE, string.Join(FileOperation.SPLIT_CHAR, Folders.Select(f => "folder_" + f).Concat(Files.Select(f => "file_" + f)).ToArray()));
TaskInfo.SetProperty(FileOperation.OPERATION_TYPE, OperationType);
TaskInfo.SetProperty(FileOperation.OWNER, ((IAccount)Thread.CurrentPrincipal.Identity).ID);
TaskInfo.SetProperty(FileOperation.PROGRESS, progress < 100 ? progress : 100);
TaskInfo.SetProperty(FileOperation.RESULT, Status);
TaskInfo.SetProperty(FileOperation.ERROR, Error);
TaskInfo.SetProperty(FileOperation.PROCESSED, successProcessed);
TaskInfo.SetProperty(FileOperation.HOLD, HoldResult);
TaskInfo.SetProperty(SOURCE, string.Join(SPLIT_CHAR, Folders.Select(f => "folder_" + f).Concat(Files.Select(f => "file_" + f)).ToArray()));
}
protected virtual int InitTotalProgressSteps()
@ -235,7 +279,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
successProcessed++;
if (Folders.Contains(folderId))
{
Status += string.Format("folder_{0}{1}", folderId, FileOperation.SPLIT_CHAR);
Status += string.Format("folder_{0}{1}", folderId, SPLIT_CHAR);
return true;
}
return false;
@ -246,7 +290,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
successProcessed++;
if (Files.Contains(fileId))
{
Status += string.Format("file_{0}{1}", fileId, FileOperation.SPLIT_CHAR);
Status += string.Format("file_{0}{1}", fileId, SPLIT_CHAR);
return true;
}
return false;
@ -257,7 +301,5 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
FillDistributedTask();
TaskInfo.PublishChanges();
}
protected abstract void Do(IServiceScope serviceScope);
}
}

View File

@ -61,7 +61,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
}
operations = operations.Where(t => t.GetProperty<Guid>(FileOperation.OWNER) == authContext.CurrentAccount.ID);
foreach (var o in operations.Where(o => DistributedTaskStatus.Running < o.Status))
foreach (var o in operations.Where(o => o.Status > DistributedTaskStatus.Running))
{
o.SetProperty(FileOperation.PROGRESS, 100);
tasks.RemoveTask(o.Id);
@ -131,6 +131,21 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
return QueueTask(authContext, op);
}
public ItemList<FileOperationResult> Delete(AuthContext authContext, TenantManager tenantManager, List<object> folders, List<object> files, bool ignoreException, bool holdResult, bool immediately, Dictionary<string, string> headers)
{
var op1 = new FileDeleteOperation<int>(ServiceProvider, new FileDeleteOperationData<int>(folders.OfType<long>().Select(Convert.ToInt32).ToList(), files.OfType<long>().Select(Convert.ToInt32).ToList(), tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers));
var op2 = new FileDeleteOperation<string>(ServiceProvider, new FileDeleteOperationData<string>(folders.OfType<string>().ToList(), files.OfType<string>().ToList(), tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers));
var op = new FileDeleteOperation(ServiceProvider, op2, op1);
return QueueTask(authContext, op);
}
private ItemList<FileOperationResult> QueueTask(AuthContext authContext, FileOperation op)
{
tasks.QueueTask(op.RunJob, op.GetDistributedTask());
return GetOperationResults(authContext);
}
private ItemList<FileOperationResult> QueueTask<T, TId>(AuthContext authContext, FileOperation<T, TId> op) where T : FileOperationData<TId>
{
@ -165,6 +180,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations
public ItemList<FileOperationResult> MoveOrCopy<T>(List<T> folders, List<T> files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary<string, string> headers)
=> FileOperationsManager.MoveOrCopy(AuthContext, TenantManager, folders, files, destFolderId, copy, resolveType, holdResult, headers);
public ItemList<FileOperationResult> Delete(List<object> folders, List<object> files, bool ignoreException, bool holdResult, bool immediately, Dictionary<string, string> headers)
{
return FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers);
}
public ItemList<FileOperationResult> Delete<T>(List<T> folders, List<T> files, bool ignoreException, bool holdResult, bool immediately, Dictionary<string, string> headers)
=> FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers);
}