Quota: transfer of the file owner id during quota change operations

This commit is contained in:
Nikolay Rechkin 2023-09-18 14:00:51 +03:00
parent 134a8ea310
commit 40f4843812
19 changed files with 272 additions and 50 deletions

View File

@ -165,22 +165,31 @@ public abstract class BaseStorage : IDataStore
public abstract Task<Stream> GetReadStreamAsync(string domain, string path, long offset);
public abstract Task<Uri> SaveAsync(string domain, string path, Stream stream);
public abstract Task<Uri> SaveAsync(string domain, string path, Stream stream, Guid ownerId);
public abstract Task<Uri> SaveAsync(string domain, string path, Stream stream, ACL acl);
public async Task<Uri> SaveAsync(string domain, string path, Stream stream, string attachmentFileName)
{
return await SaveAsync(domain, path, Guid.Empty, stream, attachmentFileName);
}
public async Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string attachmentFileName)
{
if (!string.IsNullOrEmpty(attachmentFileName))
{
return await SaveWithAutoAttachmentAsync(domain, path, stream, attachmentFileName);
return await SaveWithAutoAttachmentAsync(domain, path, ownerId, stream, attachmentFileName);
}
return await SaveAsync(domain, path, stream);
return await SaveAsync(domain, path, stream, ownerId);
}
protected abstract Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Guid ownerId, Stream stream, string attachmentFileName);
protected abstract Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Stream stream, string attachmentFileName);
public abstract Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType,
string contentDisposition);
public abstract Task<Uri> SaveAsync(string domain, string path,Guid ownerId, Stream stream, string contentType,
string contentDisposition);
public abstract Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentEncoding, int cacheDays);
#region chunking
@ -220,6 +229,7 @@ public abstract class BaseStorage : IDataStore
#endregion
public abstract Task DeleteAsync(string domain, string path);
public abstract Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive, Guid ownerId);
public abstract Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive);
public abstract Task DeleteFilesAsync(string domain, List<string> paths);
public abstract Task DeleteFilesAsync(string domain, string folderPath, DateTime fromDate, DateTime toDate);
@ -232,6 +242,7 @@ public abstract class BaseStorage : IDataStore
public abstract Task<bool> IsFileAsync(string domain, string path);
public abstract Task<bool> IsDirectoryAsync(string domain, string path);
public abstract Task DeleteDirectoryAsync(string domain, string path);
public abstract Task DeleteDirectoryAsync(string domain, string path, Guid ownerId);
public abstract Task<long> GetFileSizeAsync(string domain, string path);
public abstract Task<long> GetDirectorySizeAsync(string domain, string path);
public abstract Task<long> ResetQuotaAsync(string domain);
@ -308,6 +319,10 @@ public abstract class BaseStorage : IDataStore
{
await DeleteDirectoryAsync(string.Empty, path);
}
public async Task DeleteDirectoryAsync(Guid ownerId, string path)
{
await DeleteDirectoryAsync(string.Empty, path, ownerId);
}
public async Task<long> GetFileSizeAsync(string path)
{
@ -353,20 +368,28 @@ public abstract class BaseStorage : IDataStore
string contentDisposition);
internal async Task QuotaUsedAddAsync(string domain, long size, bool quotaCheckFileSize = true)
{
await QuotaUsedAddAsync(domain, size, Guid.Empty, quotaCheckFileSize);
}
internal async Task QuotaUsedAddAsync(string domain, long size, Guid ownerId, bool quotaCheckFileSize = true)
{
if (QuotaController != null)
{
await QuotaController.QuotaUsedAddAsync(Modulename, domain, DataList.GetData(domain), size, quotaCheckFileSize);
await QuotaController.QuotaUsedAddAsync(Modulename, domain, DataList.GetData(domain), size, ownerId, quotaCheckFileSize);
var(name, value) = await _tenantQuotaFeatureStatHelper.GetStatAsync<MaxTotalSizeFeature, long>();
_ = _quotaSocketManager.ChangeQuotaUsedValueAsync(name, value);
}
}
internal async Task QuotaUsedDeleteAsync(string domain, long size)
{
await QuotaUsedDeleteAsync(domain, size, Guid.Empty);
}
internal async Task QuotaUsedDeleteAsync(string domain, long size, Guid ownerId)
{
if (QuotaController != null)
{
await QuotaController.QuotaUsedDeleteAsync(Modulename, domain, DataList.GetData(domain), size);
await QuotaController.QuotaUsedDeleteAsync(Modulename, domain, DataList.GetData(domain), size, ownerId);
var (name, value) = await _tenantQuotaFeatureStatHelper.GetStatAsync<MaxTotalSizeFeature, long>();
_ = _quotaSocketManager.ChangeQuotaUsedValueAsync(name, value);
}

View File

@ -136,6 +136,10 @@ public class DiscDataStore : BaseStorage
throw new FileNotFoundException("File not found", Path.GetFullPath(target));
}
public override Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string contentType, string contentDisposition)
{
return SaveAsync(domain, path, stream, ownerId);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType, string contentDisposition)
{
return SaveAsync(domain, path, stream);
@ -151,6 +155,10 @@ public class DiscDataStore : BaseStorage
}
public override async Task<Uri> SaveAsync(string domain, string path, Stream stream)
{
return await SaveAsync(domain, path, stream, Guid.Empty);
}
public override async Task<Uri> SaveAsync(string domain, string path, Stream stream, Guid ownerId)
{
Logger.DebugSavePath(path);
@ -158,7 +166,7 @@ public class DiscDataStore : BaseStorage
if (EnableQuotaCheck(domain))
{
await QuotaController.QuotaUsedCheckAsync(buffered.Length);
await QuotaController.QuotaUsedCheckAsync(buffered.Length, ownerId);
}
ArgumentNullException.ThrowIfNull(path);
@ -189,7 +197,7 @@ public class DiscDataStore : BaseStorage
fslen = fs.Length;
}
await QuotaUsedAddAsync(domain, fslen);
await QuotaUsedAddAsync(domain, fslen, ownerId);
_crypt.EncryptFile(target);
@ -294,6 +302,10 @@ public class DiscDataStore : BaseStorage
}
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
{
await DeleteFilesAsync(domain, folderPath, pattern, recursive, Guid.Empty);
}
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive, Guid ownerId)
{
ArgumentNullException.ThrowIfNull(folderPath);
@ -306,7 +318,7 @@ public class DiscDataStore : BaseStorage
{
var size = _crypt.GetFileSize(entry);
File.Delete(entry);
await QuotaUsedDeleteAsync(domain, size);
await QuotaUsedDeleteAsync(domain, size, ownerId);
}
}
else
@ -406,6 +418,11 @@ public class DiscDataStore : BaseStorage
}
public override async Task DeleteDirectoryAsync(string domain, string path)
{
await DeleteDirectoryAsync(domain, path, Guid.Empty);
}
public override async Task DeleteDirectoryAsync(string domain, string path, Guid ownerId)
{
ArgumentNullException.ThrowIfNull(path);
@ -444,7 +461,7 @@ public class DiscDataStore : BaseStorage
Directory.Delete(targetDir, true);
await QuotaUsedDeleteAsync(domain, size);
await QuotaUsedDeleteAsync(domain, size, ownerId);
}
public override Task<long> GetFileSizeAsync(string domain, string path)
@ -672,7 +689,10 @@ public class DiscDataStore : BaseStorage
throw new FileNotFoundException("file not found", target);
}
}
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Guid ownerId, Stream stream, string attachmentFileName)
{
return SaveAsync(domain, path, stream, ownerId);
}
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Stream stream, string attachmentFileName)
{
return SaveAsync(domain, path, stream);

View File

@ -167,6 +167,11 @@ public class GoogleCloudStorage : BaseStorage
return SaveAsync(domain, path, stream, string.Empty, string.Empty);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, Guid ownerId)
{
return SaveAsync(domain, path, ownerId, stream, string.Empty, string.Empty);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, ACL acl)
{
return SaveAsync(domain, path, stream, null, null, acl);
@ -174,7 +179,11 @@ public class GoogleCloudStorage : BaseStorage
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType, string contentDisposition)
{
return SaveAsync(domain, path, stream, contentType, contentDisposition, ACL.Auto);
return SaveAsync(domain, path, Guid.Empty, stream, contentType, contentDisposition);
}
public override Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string contentType, string contentDisposition)
{
return SaveAsync(domain, path, ownerId, stream, contentType, contentDisposition, ACL.Auto);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentEncoding, int cacheDays)
@ -188,6 +197,12 @@ public class GoogleCloudStorage : BaseStorage
}
public async Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType,
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5)
{
return await SaveAsync(domain, path, Guid.Empty, stream, contentType,
contentDisposition, acl, contentEncoding, cacheDays);
}
public async Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string contentType,
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5)
{
@ -195,7 +210,7 @@ public class GoogleCloudStorage : BaseStorage
if (EnableQuotaCheck(domain))
{
await QuotaController.QuotaUsedCheckAsync(buffered.Length);
await QuotaController.QuotaUsedCheckAsync(buffered.Length, ownerId);
}
var mime = string.IsNullOrEmpty(contentType)
@ -254,6 +269,10 @@ public class GoogleCloudStorage : BaseStorage
}
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
{
await DeleteFilesAsync(domain, folderPath, pattern, recursive, Guid.Empty);
}
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive, Guid ownerId)
{
using var storage = GetStorage();
@ -273,7 +292,7 @@ public class GoogleCloudStorage : BaseStorage
await foreach (var obj in objToDel)
{
await storage.DeleteObjectAsync(_bucket, obj.Name);
await QuotaUsedDeleteAsync(domain, Convert.ToInt64(obj.Size));
await QuotaUsedDeleteAsync(domain, Convert.ToInt64(obj.Size), ownerId);
}
}
@ -443,6 +462,10 @@ public class GoogleCloudStorage : BaseStorage
}
public override async Task DeleteDirectoryAsync(string domain, string path)
{
await DeleteDirectoryAsync(domain, path, Guid.Empty);
}
public override async Task DeleteDirectoryAsync(string domain, string path, Guid ownerId)
{
using var storage = GetStorage();
@ -458,7 +481,7 @@ public class GoogleCloudStorage : BaseStorage
if (string.IsNullOrEmpty(QuotaController.ExcludePattern) ||
!Path.GetFileName(obj.Name).StartsWith(QuotaController.ExcludePattern))
{
await QuotaUsedDeleteAsync(domain, Convert.ToInt64(obj.Size));
await QuotaUsedDeleteAsync(domain, Convert.ToInt64(obj.Size), ownerId);
}
}
}
@ -768,13 +791,17 @@ public class GoogleCloudStorage : BaseStorage
}
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Stream stream, string attachmentFileName)
{
return SaveWithAutoAttachmentAsync(domain, path, Guid.Empty, stream, attachmentFileName);
}
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Guid ownerId, Stream stream, string attachmentFileName)
{
var contentDisposition = $"attachment; filename={HttpUtility.UrlPathEncode(attachmentFileName)};";
if (attachmentFileName.Any(c => c >= 0 && c <= 127))
{
contentDisposition = $"attachment; filename*=utf-8''{HttpUtility.UrlPathEncode(attachmentFileName)};";
}
return SaveAsync(domain, path, stream, null, contentDisposition);
return SaveAsync(domain, path, ownerId, stream, null, contentDisposition);
}
private StorageClient GetStorage()

View File

@ -147,6 +147,17 @@ public interface IDataStore
/// <returns></returns>
Task<Uri> SaveAsync(string domain, string path, Stream stream, string attachmentFileName);
/// <summary>
/// Saves the contents of the stream in the repository.
/// </summary>
/// <param name="domain"></param>
/// <param name="path"></param>
/// <param name="ownerId"></param>
/// <param name="stream"></param>
/// <param name="attachmentFileName"></param>
/// <returns></returns>
Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string attachmentFileName);
/// <summary>
/// Saves the contents of the stream in the repository.
/// </summary>
@ -316,6 +327,7 @@ public interface IDataStore
Task<bool> IsFileAsync(string path);
Task<bool> IsDirectoryAsync(string path);
Task DeleteDirectoryAsync(string path);
Task DeleteDirectoryAsync(Guid ownerId, string path);
Task<long> GetFileSizeAsync(string path);
Task<long> GetDirectorySizeAsync(string path);
Task<Uri> CopyAsync(string path, string newdomain, string newpath);

View File

@ -29,13 +29,15 @@ namespace ASC.Data.Storage;
public interface IQuotaController
{
//quotaCheckFileSize:hack for Backup bug 48873
Task QuotaUsedAddAsync(string module, string domain, string dataTag, long size, Guid ownerID, bool quotaCheckFileSize = true);
Task QuotaUsedAddAsync(string module, string domain, string dataTag, long size, bool quotaCheckFileSize = true);
Task QuotaUsedDeleteAsync(string module, string domain, string dataTag, long size);
Task QuotaUsedDeleteAsync(string module, string domain, string dataTag, long size, Guid ownerId);
Task QuotaUsedSetAsync(string module, string domain, string dataTag, long size);
Task QuotaUsedCheckAsync(long size);
Task QuotaUsedCheckAsync(long size, Guid ownerId);
string ExcludePattern { get; set; }
}

View File

@ -169,9 +169,13 @@ public class RackspaceCloudStorage : BaseStorage
return GetReadStreamAsync(domain, path, offset);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, Guid ownerId)
{
return SaveAsync(domain, path, ownerId, stream, string.Empty, string.Empty);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream)
{
return SaveAsync(domain, path, stream, string.Empty, string.Empty);
return SaveAsync(domain, path, Guid.Empty,stream, string.Empty, string.Empty);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, ACL acl)
@ -179,6 +183,10 @@ public class RackspaceCloudStorage : BaseStorage
return SaveAsync(domain, path, stream, null, null, acl);
}
public override Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string contentType, string contentDisposition)
{
return SaveAsync(domain, path, ownerId, stream, contentType, contentDisposition, ACL.Auto);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType, string contentDisposition)
{
return SaveAsync(domain, path, stream, contentType, contentDisposition, ACL.Auto);
@ -195,6 +203,13 @@ public class RackspaceCloudStorage : BaseStorage
}
public async Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType,
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5,
DateTime? deleteAt = null, long? deleteAfter = null)
{
return await SaveAsync(domain, path, Guid.Empty, stream, contentType, contentDisposition, acl, contentEncoding, cacheDays, deleteAt, deleteAfter);
}
public async Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string contentType,
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5,
DateTime? deleteAt = null, long? deleteAfter = null)
{
@ -202,7 +217,7 @@ public class RackspaceCloudStorage : BaseStorage
if (EnableQuotaCheck(domain))
{
await QuotaController.QuotaUsedCheckAsync(buffered.Length);
await QuotaController.QuotaUsedCheckAsync(buffered.Length, ownerId);
}
var client = GetClient();
@ -283,7 +298,7 @@ public class RackspaceCloudStorage : BaseStorage
_region
);
await QuotaUsedAddAsync(domain, buffered.Length);
await QuotaUsedAddAsync(domain, buffered.Length, ownerId);
return await GetUriAsync(domain, path);
@ -302,6 +317,10 @@ public class RackspaceCloudStorage : BaseStorage
}
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive)
{
await DeleteFilesAsync(domain, folderPath, pattern, recursive, Guid.Empty);
}
public override async Task DeleteFilesAsync(string domain, string folderPath, string pattern, bool recursive, Guid ownerId)
{
var client = GetClient();
@ -320,7 +339,7 @@ public class RackspaceCloudStorage : BaseStorage
if (QuotaController != null)
{
await QuotaUsedDeleteAsync(domain, files.Select(x => x.Bytes).Sum());
await QuotaUsedDeleteAsync(domain, files.Select(x => x.Bytes).Sum(), ownerId);
}
}
@ -468,6 +487,10 @@ public class RackspaceCloudStorage : BaseStorage
}
public override async Task DeleteDirectoryAsync(string domain, string path)
{
await DeleteDirectoryAsync(domain, path, Guid.Empty);
}
public override async Task DeleteDirectoryAsync(string domain, string path, Guid ownerId)
{
var client = GetClient();
@ -482,7 +505,7 @@ public class RackspaceCloudStorage : BaseStorage
if (string.IsNullOrEmpty(QuotaController.ExcludePattern) ||
!Path.GetFileName(obj.Name).StartsWith(QuotaController.ExcludePattern))
{
await QuotaUsedDeleteAsync(domain, obj.Bytes);
await QuotaUsedDeleteAsync(domain, obj.Bytes, ownerId);
}
}
}
@ -678,6 +701,10 @@ public class RackspaceCloudStorage : BaseStorage
#endregion
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Stream stream, string attachmentFileName)
{
return SaveWithAutoAttachmentAsync(domain, path, Guid.Empty, stream, attachmentFileName);
}
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Guid ownerId, Stream stream, string attachmentFileName)
{
var contentDisposition = $"attachment; filename={HttpUtility.UrlPathEncode(attachmentFileName)};";
if (attachmentFileName.Any(c => c >= 0 && c <= 127))
@ -685,7 +712,7 @@ public class RackspaceCloudStorage : BaseStorage
contentDisposition = $"attachment; filename*=utf-8''{HttpUtility.UrlPathEncode(attachmentFileName)};";
}
return SaveAsync(domain, path, stream, null, contentDisposition);
return SaveAsync(domain, path, ownerId, stream, null, contentDisposition);
}
private string MakePath(string domain, string path)

View File

@ -259,7 +259,11 @@ public class S3Storage : BaseStorage
throw;
}
}
public override Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string contentType,
string contentDisposition)
{
return SaveAsync(domain, path, ownerId, stream, contentType, contentDisposition, ACL.Auto);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType,
string contentDisposition)
{
@ -273,12 +277,18 @@ public class S3Storage : BaseStorage
public async Task<Uri> SaveAsync(string domain, string path, Stream stream, string contentType,
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5)
{
return await SaveAsync(domain, path, Guid.Empty, stream, contentType,
contentDisposition, acl, contentEncoding, cacheDays);
}
public async Task<Uri> SaveAsync(string domain, string path, Guid ownerId, Stream stream, string contentType,
string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5)
{
var buffered = _tempStream.GetBuffered(stream);
if (EnableQuotaCheck(domain))
{
await QuotaController.QuotaUsedCheckAsync(buffered.Length);
await QuotaController.QuotaUsedCheckAsync(buffered.Length, ownerId);
}
using var client = GetClient();
@ -333,12 +343,15 @@ public class S3Storage : BaseStorage
//await InvalidateCloudFrontAsync(MakePath(domain, path));
await QuotaUsedAddAsync(domain, buffered.Length);
await QuotaUsedAddAsync(domain, buffered.Length, ownerId);
return await GetUriAsync(domain, path);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream, Guid ownerId)
{
return SaveAsync(domain, path, ownerId, stream, string.Empty, string.Empty);
}
public override Task<Uri> SaveAsync(string domain, string path, Stream stream)
{
return SaveAsync(domain, path, stream, string.Empty, string.Empty);
@ -560,6 +573,10 @@ public class S3Storage : BaseStorage
}
public override async Task DeleteFilesAsync(string domain, string path, string pattern, bool recursive)
{
await DeleteFilesAsync(domain, path, pattern, recursive, Guid.Empty);
}
public override async Task DeleteFilesAsync(string domain, string path, string pattern, bool recursive, Guid ownerId)
{
var makedPath = MakePath(domain, path) + '/';
var obj = await GetS3ObjectsAsync(domain, path);
@ -586,7 +603,7 @@ public class S3Storage : BaseStorage
if (string.IsNullOrEmpty(QuotaController.ExcludePattern) ||
!Path.GetFileName(s3Object.Key).StartsWith(QuotaController.ExcludePattern))
{
await QuotaUsedDeleteAsync(domain, s3Object.Size);
await QuotaUsedDeleteAsync(domain, s3Object.Size, ownerId);
}
}
}
@ -885,6 +902,10 @@ public class S3Storage : BaseStorage
}
public override async Task DeleteDirectoryAsync(string domain, string path)
{
await DeleteDirectoryAsync(domain, path, Guid.Empty);
}
public override async Task DeleteDirectoryAsync(string domain, string path, Guid ownerId)
{
await DeleteFilesAsync(domain, path, "*", true);
}
@ -1077,13 +1098,17 @@ public class S3Storage : BaseStorage
}
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Stream stream, string attachmentFileName)
{
return SaveWithAutoAttachmentAsync(domain, path, Guid.Empty, stream, attachmentFileName);
}
protected override Task<Uri> SaveWithAutoAttachmentAsync(string domain, string path, Guid ownerId, Stream stream, string attachmentFileName)
{
var contentDisposition = $"attachment; filename={HttpUtility.UrlPathEncode(attachmentFileName)};";
if (attachmentFileName.Any(c => c >= 0 && c <= 127))
{
contentDisposition = $"attachment; filename*=utf-8''{HttpUtility.UrlPathEncode(attachmentFileName)};";
}
return SaveAsync(domain, path, stream, null, contentDisposition);
return SaveAsync(domain, path, ownerId, stream, null, contentDisposition);
}

View File

@ -70,19 +70,30 @@ public class TenantQuotaController : IQuotaController
}
public async Task QuotaUsedAddAsync(string module, string domain, string dataTag, long size, bool quotaCheckFileSize = true)
{
await QuotaUsedAddAsync(module, domain, dataTag, size, Guid.Empty, quotaCheckFileSize);
}
public async Task QuotaUsedAddAsync(string module, string domain, string dataTag, long size, Guid ownerId, bool quotaCheckFileSize = true)
{
size = Math.Abs(size);
if (UsedInQuota(dataTag))
{
await QuotaUsedCheckAsync(size, quotaCheckFileSize);
await QuotaUsedCheckAsync(size, quotaCheckFileSize, ownerId);
CurrentSize += size;
}
await SetTenantQuotaRowAsync(module, domain, size, dataTag, true, Guid.Empty);
await SetTenantQuotaRowAsync(module, domain, size, dataTag, true, _authContext.CurrentAccount.ID);
if (ownerId != Core.Configuration.Constants.CoreSystem.ID)
{
await SetTenantQuotaRowAsync(module, domain, size, dataTag, true, ownerId != Guid.Empty ? ownerId : _authContext.CurrentAccount.ID);
}
}
public async Task QuotaUsedDeleteAsync(string module, string domain, string dataTag, long size)
{
await QuotaUsedDeleteAsync(module, domain, dataTag, size, Guid.Empty);
}
public async Task QuotaUsedDeleteAsync(string module, string domain, string dataTag, long size)
public async Task QuotaUsedDeleteAsync(string module, string domain, string dataTag, long size, Guid ownerId)
{
size = -Math.Abs(size);
if (UsedInQuota(dataTag))
@ -91,7 +102,10 @@ public class TenantQuotaController : IQuotaController
}
await SetTenantQuotaRowAsync(module, domain, size, dataTag, true, Guid.Empty);
await SetTenantQuotaRowAsync(module, domain, size, dataTag, true, _authContext.CurrentAccount.ID);
if (ownerId != Core.Configuration.Constants.CoreSystem.ID)
{
await SetTenantQuotaRowAsync(module, domain, size, dataTag, true, ownerId != Guid.Empty ? ownerId : _authContext.CurrentAccount.ID);
}
}
public async Task QuotaUsedSetAsync(string module, string domain, string dataTag, long size)
@ -105,12 +119,12 @@ public class TenantQuotaController : IQuotaController
await SetTenantQuotaRowAsync(module, domain, size, dataTag, false, Guid.Empty);
}
public async Task QuotaUsedCheckAsync(long size)
public async Task QuotaUsedCheckAsync(long size, Guid ownedId)
{
await QuotaUsedCheckAsync(size, true);
await QuotaUsedCheckAsync(size, true, ownedId);
}
public async Task QuotaUsedCheckAsync(long size, bool quotaCheckFileSize)
public async Task QuotaUsedCheckAsync(long size, bool quotaCheckFileSize, Guid ownerId)
{
var quota = await _tenantManager.GetTenantQuotaAsync(_tenant);
if (quota != null)
@ -125,6 +139,25 @@ public class TenantQuotaController : IQuotaController
await _maxTotalSizeChecker.CheckAddAsync(_tenant, CurrentSize + size);
}
}
//TODO
/* var quotaSettings = TenantUserQuotaSettings.Load();
if (quotaSettings.EnableUserQuota)
{
var userQuotaSettings = UserQuotaSettings.LoadForUser(ownedId);
var quotaLimit = userQuotaSettings.UserQuota;
if (quotaLimit != -1)
{
var userUsedSpace = Math.Max(0, CoreContext.TenantManager.FindUserQuotaRows(_tenant, ownedId).Where(r => !string.IsNullOrEmpty(r.Tag)).Where(r => r.Tag != Guid.Empty.ToString()).Sum(r => r.Counter));
if (quotaLimit - userUsedSpace < size)
{
throw new TenantQuotaException(string.Format("Exceeds the maximum file size ({0}MB)", BytesToMegabytes(quotaLimit)));
}
}
}
*/
}

View File

@ -177,6 +177,12 @@ public interface IFileDao<T>
/// <param name="fileId">file id</param>
Task DeleteFileAsync(T fileId);
/// <summary>
/// Deletes a file including all previous versions
/// </summary>
/// <param name="fileId">file id</param>
/// <param name="ownerId">file owner id</param>
Task DeleteFileAsync(T fileId, Guid ownerId);
/// <summary>
/// Checks whether or not file
/// </summary>
/// <param name="title">file name</param>

View File

@ -345,7 +345,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
if (checkQuota && _coreBaseSettings.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace"))
{
var personalMaxSpace = await _coreConfiguration.PersonalMaxSpaceAsync(_settingsManager);
if (personalMaxSpace - await _globalSpace.GetUserUsedSpaceAsync(file.Id == default ? _authContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength)
if (personalMaxSpace - await _globalSpace.GetUserUsedSpaceAsync(file.GetFileQuotaOwner()) < file.ContentLength)
{
throw FileSizeComment.GetPersonalFreeSpaceException(personalMaxSpace);
}
@ -471,7 +471,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
if (isNew)
{
var stored = await (await _globalStore.GetStoreAsync()).IsDirectoryAsync(GetUniqFileDirectory(file.Id));
await DeleteFileAsync(file.Id, stored);
await DeleteFileAsync(file.Id, stored, file.GetFileQuotaOwner());
}
else if (!await IsExistOnStorageAsync(file))
{
@ -529,7 +529,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
if (_coreBaseSettings.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace"))
{
var personalMaxSpace = await _coreConfiguration.PersonalMaxSpaceAsync(_settingsManager);
if (personalMaxSpace - await _globalSpace.GetUserUsedSpaceAsync(file.Id == default ? _authContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength)
if (personalMaxSpace - await _globalSpace.GetUserUsedSpaceAsync(file.GetFileQuotaOwner()) < file.ContentLength)
{
throw FileSizeComment.GetPersonalFreeSpaceException(personalMaxSpace);
}
@ -653,15 +653,33 @@ internal class FileDao : AbstractDao, IFileDao<int>
private async Task SaveFileStreamAsync(File<int> file, Stream stream)
{
await (await _globalStore.GetStoreAsync()).SaveAsync(string.Empty, GetUniqFilePath(file), stream, file.Title);
var folderDao = _daoFactory.GetFolderDao<int>();
var folder = await folderDao.GetFolderAsync(file.FolderIdDisplay);
if (DocSpaceHelper.IsRoom(folder.FolderType))
{
file.RootCreateBy = folder.CreateBy;
file.RootFolderType = folder.FolderType;
}
else {
file.RootCreateBy = folder.RootCreateBy;
file.RootFolderType = folder.RootFolderType;
}
await (await _globalStore.GetStoreAsync()).SaveAsync(string.Empty, GetUniqFilePath(file), file.GetFileQuotaOwner(), stream, file.Title);
}
public async Task DeleteFileAsync(int fileId)
{
await DeleteFileAsync(fileId, true);
await DeleteFileAsync(fileId, Guid.Empty);
}
private async ValueTask DeleteFileAsync(int fileId, bool deleteFolder)
public async Task DeleteFileAsync(int fileId, Guid ownerId)
{
await DeleteFileAsync(fileId, true, ownerId);
}
private async ValueTask DeleteFileAsync(int fileId, bool deleteFolder, Guid ownerId)
{
if (fileId == default)
{
@ -707,7 +725,7 @@ internal class FileDao : AbstractDao, IFileDao<int>
var tenantId = _tenantManager.GetCurrentTenant().Id;
_tenantQuotaController.Init(tenantId, ThumbnailTitle);
var store = await _storageFactory.GetStorageAsync(tenantId, FileConstant.StorageModule, _tenantQuotaController);
await store.DeleteDirectoryAsync(GetUniqFileDirectory(fileId));
await store.DeleteDirectoryAsync(ownerId, GetUniqFileDirectory(fileId));
}
if (toDeleteFile != null)

View File

@ -57,9 +57,10 @@ public class File<T> : FileEntry<T>, IFileEntry<T>
public File(
FileHelper fileHelper,
Global global,
SecurityContext securityContext,
GlobalFolderHelper globalFolderHelper,
FilesSettingsHelper filesSettingsHelper,
FileDateTime fileDateTime) : base(fileHelper, global, globalFolderHelper, filesSettingsHelper, fileDateTime)
FileDateTime fileDateTime) : base(fileHelper, global, securityContext, globalFolderHelper, filesSettingsHelper, fileDateTime)
{
Version = 1;
VersionGroup = 1;

View File

@ -120,6 +120,7 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
public IDictionary<FilesSecurityActions, bool> Security { get; set; }
private T _folderIdDisplay;
private readonly SecurityContext _securityContext;
private readonly GlobalFolderHelper _globalFolderHelper;
private readonly FilesSettingsHelper _filesSettingsHelper;
private readonly FileDateTime _fileDateTime;
@ -130,10 +131,12 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
protected FileEntry(
FileHelper fileHelper,
Global global,
SecurityContext securityContext,
GlobalFolderHelper globalFolderHelper,
FilesSettingsHelper filesSettingsHelper,
FileDateTime fileDateTime) : base(fileHelper, global)
{
_securityContext = securityContext;
_globalFolderHelper = globalFolderHelper;
_filesSettingsHelper = filesSettingsHelper;
_fileDateTime = fileDateTime;
@ -188,4 +191,15 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
{
return Title;
}
public Guid GetFileQuotaOwner()
{
return
RootFolderType == FolderType.USER || RootFolderType == FolderType.DEFAULT || RootFolderType == FolderType.TRASH ?
RootCreateBy :
RootFolderType == FolderType.Privacy && CreateBy == _securityContext.CurrentAccount.ID ?
CreateBy :
ASC.Core.Configuration.Constants.CoreSystem.ID;
}
}

View File

@ -94,9 +94,10 @@ public class Folder<T> : FileEntry<T>, IFolder
public Folder(
FileHelper fileHelper,
Global global,
SecurityContext securityContext,
GlobalFolderHelper globalFolderHelper,
FilesSettingsHelper filesSettingsHelper,
FileDateTime fileDateTime) : base(fileHelper, global, globalFolderHelper, filesSettingsHelper, fileDateTime)
FileDateTime fileDateTime) : base(fileHelper, global, securityContext, globalFolderHelper, filesSettingsHelper, fileDateTime)
{
Title = string.Empty;
FileEntryType = FileEntryType.Folder;

View File

@ -295,11 +295,15 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
}
public async Task DeleteFileAsync(string fileId)
{
await DeleteFileAsync(fileId, Guid.Empty);
}
public async Task DeleteFileAsync(string fileId, Guid ownerId)
{
var selector = _selectorFactory.GetSelector(fileId);
var fileDao = selector.GetFileDao(fileId);
await fileDao.DeleteFileAsync(selector.ConvertId(fileId));
await fileDao.DeleteFileAsync(selector.ConvertId(fileId), ownerId);
}
public async Task<bool> IsExistAsync(string title, object folderId)

View File

@ -333,7 +333,10 @@ internal class SharePointFileDao : SharePointDaoBase, IFileDao<string>
{
return await SaveFileAsync(file, fileStream);
}
public async Task DeleteFileAsync(string fileId,Guid ownerId)
{
await DeleteFileAsync(fileId);
}
public async Task DeleteFileAsync(string fileId)
{
await SharePointProviderInfo.DeleteFileAsync(fileId);

View File

@ -173,7 +173,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,
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, int offset = 0, int count = -1)
{
if (filterType == FilterType.FoldersOnly)
@ -369,7 +369,10 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao<string>
{
return await SaveFileAsync(file, fileStream);
}
public async Task DeleteFileAsync(string fileId, Guid ownerId)
{
await DeleteFileAsync(fileId);
}
public async Task DeleteFileAsync(string fileId)
{
var file = GetFileById(fileId);

View File

@ -361,7 +361,10 @@ internal abstract class ThirdPartyFileDao<TFile, TFolder, TItem> : IFileDao<stri
{
return SaveFileAsync(file, fileStream);
}
public async Task DeleteFileAsync(string fileId, Guid ownerId)
{
await DeleteFileAsync(fileId);
}
public async Task DeleteFileAsync(string fileId)
{
var file = await Dao.GetFileAsync(fileId);

View File

@ -324,7 +324,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
{
try
{
await FileDao.DeleteFileAsync(file.Id);
await FileDao.DeleteFileAsync(file.Id, file.GetFileQuotaOwner());
if (_headers != null)
{

View File

@ -1947,7 +1947,7 @@ public class EntryManager
await foreach (var file in files)
{
_logger.InformationDeletefile(file.Id.ToString(), parentId.ToString());
await fileDao.DeleteFileAsync(file.Id);
await fileDao.DeleteFileAsync(file.Id, file.GetFileQuotaOwner());
await _socketManager.DeleteFileAsync(file);
await linkDao.DeleteAllLinkAsync(file.Id.ToString());