Quota: transfer of the file owner id during quota change operations
This commit is contained in:
parent
134a8ea310
commit
40f4843812
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user