refactoring thirdParty
This commit is contained in:
parent
d0f5f29a3b
commit
858e0dc300
@ -28,7 +28,7 @@ namespace ASC.Files.Core;
|
||||
|
||||
public interface IProviderInfo : IDisposable
|
||||
{
|
||||
int ID { get; set; }
|
||||
int ProviderId { get; set; }
|
||||
string ProviderKey { get; }
|
||||
Guid Owner { get; }
|
||||
FolderType RootFolderType { get; }
|
||||
|
47
products/ASC.Files/Core/Core/Thirdparty/AbstractFileDao.cs
vendored
Normal file
47
products/ASC.Files/Core/Core/Thirdparty/AbstractFileDao.cs
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using File = System.IO.File;
|
||||
|
||||
namespace ASC.Files.Core.Core.Thirdparty;
|
||||
internal class AbstractFileDao<TFile, TFolder, TItem> : IFileDao<string>
|
||||
{
|
||||
private readonly IDaoBase<TFile, TFolder, TItem> _dao;
|
||||
private readonly IProviderInfo _providerInfo;
|
||||
public async Task InvalidateCacheAsync(string fileId)
|
||||
{
|
||||
var boxFileId = _dao.MakeId(fileId);
|
||||
await _providerInfo.CacheResetAsync(boxFileId, true);
|
||||
|
||||
var boxFile = await GetBoxFileAsync(fileId);
|
||||
var parentPath = GetParentFolderId(boxFile);
|
||||
|
||||
if (parentPath != null)
|
||||
{
|
||||
await ProviderInfo.CacheResetAsync(parentPath);
|
||||
}
|
||||
}
|
||||
}
|
327
products/ASC.Files/Core/Core/Thirdparty/AbstractProviderInfo.cs
vendored
Normal file
327
products/ASC.Files/Core/Core/Thirdparty/AbstractProviderInfo.cs
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.Files.Core.Core.Thirdparty;
|
||||
|
||||
public abstract class AbstractProviderInfo<TFile, TFolder, TItem, TProvider> : IProviderInfo
|
||||
where TFile : class
|
||||
where TFolder : class
|
||||
where TItem : class
|
||||
where TProvider : Consumer, IOAuthProvider, new()
|
||||
{
|
||||
internal abstract string Selector { get; }
|
||||
public DisposableWrapper Wrapper { get; }
|
||||
|
||||
public AbstractProviderInfo(DisposableWrapper wrapper)
|
||||
{
|
||||
Wrapper = wrapper;
|
||||
}
|
||||
|
||||
public DateTime CreateOn { get; set; }
|
||||
public string CustomerTitle { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
public FolderType FolderType { get; set; }
|
||||
public bool HasLogo { get; set; }
|
||||
public int ProviderId { get; set; }
|
||||
public Guid Owner { get; set; }
|
||||
public bool Private { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
public string RootFolderId => $"{Selector}-" + ProviderId;
|
||||
public FolderType RootFolderType { get; set; }
|
||||
public OAuth20Token Token { get; set; }
|
||||
internal bool StorageOpened => Wrapper.TryGetStorage(ProviderId, out var storage) && storage.IsOpened;
|
||||
|
||||
private readonly ProviderInfoHelper _providerInfoHelper;
|
||||
|
||||
internal Task<IThirdPartyStorage<TFile, TFolder, TItem>> StorageAsync
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Wrapper.TryGetStorage<IThirdPartyStorage<TFile, TFolder, TItem>>(ProviderId, out var storage) || !storage.IsOpened)
|
||||
{
|
||||
return Wrapper.CreateStorageAsync<IThirdPartyStorage<TFile, TFolder, TItem>, TProvider>(Token, ProviderId);
|
||||
}
|
||||
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> CheckAccessAsync()
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await storage.CheckAccessAsync();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (StorageOpened)
|
||||
{
|
||||
StorageAsync.Result.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public Task InvalidateStorageAsync()
|
||||
{
|
||||
if (Wrapper != null)
|
||||
{
|
||||
Wrapper.Dispose();
|
||||
}
|
||||
|
||||
return CacheResetAsync();
|
||||
}
|
||||
|
||||
public void UpdateTitle(string newtitle)
|
||||
{
|
||||
CustomerTitle = newtitle;
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(string id = null, bool? isFile = null)
|
||||
{
|
||||
return _providerInfoHelper.CacheResetAsync(ProviderId, id, isFile);
|
||||
}
|
||||
|
||||
internal async Task<TFile> GetFileAsync(string fileId)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _providerInfoHelper.GetFileAsync(storage, ProviderId, fileId, Selector);
|
||||
}
|
||||
|
||||
internal async Task<TFolder> GetFolderAsync(string folderId)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _providerInfoHelper.GetFolderAsync(storage, ProviderId, folderId, Selector);
|
||||
}
|
||||
|
||||
internal async Task<List<TItem>> GetItemsAsync(string folderId)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _providerInfoHelper.GetItemsAsync(storage, ProviderId, folderId, Selector);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await storage.GetThumbnailAsync(fileId, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Singletone]
|
||||
public class ProviderInfoHelper
|
||||
{
|
||||
private readonly ICache _cacheChildItems;
|
||||
private readonly TimeSpan _cacheExpiration = TimeSpan.FromMinutes(1);
|
||||
private readonly ICache _cacheFile;
|
||||
private readonly ICache _cacheFolder;
|
||||
private readonly ICacheNotify<BoxCacheItem> _cacheNotify;
|
||||
private readonly IEnumerable<string> _selectors = Selectors.StoredCache.Select(s => s.Id);
|
||||
|
||||
public ProviderInfoHelper(ICacheNotify<BoxCacheItem> cacheNotify, ICache cache)
|
||||
{
|
||||
_cacheFile = cache;
|
||||
_cacheFolder = cache;
|
||||
_cacheChildItems = cache;
|
||||
_cacheNotify = cacheNotify;
|
||||
foreach (var selector in _selectors)
|
||||
{
|
||||
_cacheNotify.Subscribe((i) =>
|
||||
{
|
||||
if (i.ResetAll)
|
||||
{
|
||||
_cacheChildItems.Remove(new Regex($"^{selector}-" + i.Key + ".*"));
|
||||
_cacheFile.Remove(new Regex($"^{selector}f-" + i.Key + ".*"));
|
||||
_cacheFolder.Remove(new Regex($"^{selector}d-" + i.Key + ".*"));
|
||||
}
|
||||
|
||||
if (!i.IsFileExists)
|
||||
{
|
||||
_cacheChildItems.Remove($"{selector}-" + i.Key);
|
||||
|
||||
_cacheFolder.Remove($"{selector}d-" + i.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i.IsFile)
|
||||
{
|
||||
_cacheFile.Remove($"{selector}f-" + i.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cacheFolder.Remove($"{selector}d-" + i.Key);
|
||||
}
|
||||
}
|
||||
}, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(int ThitdId, string id = null, bool? isFile = null)
|
||||
{
|
||||
var key = ThitdId + "-";
|
||||
if (id == null)
|
||||
{
|
||||
await _cacheNotify.PublishAsync(new BoxCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove);
|
||||
}
|
||||
else
|
||||
{
|
||||
key += id;
|
||||
|
||||
await _cacheNotify.PublishAsync(new BoxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal async ValueTask<TFile> GetFileAsync<TFile>(IThirdPartyFileStorage<TFile> storage, int id, string fileId, string selector) where TFile : class
|
||||
{
|
||||
var file = _cacheFile.Get<TFile>($"{selector}f-" + id + "-" + fileId);
|
||||
if (file == null)
|
||||
{
|
||||
file = await storage.GetFileAsync(fileId);
|
||||
if (file != null)
|
||||
{
|
||||
_cacheFile.Insert($"{selector}f-" + id + "-" + fileId, file, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
internal async Task<TFolder> GetFolderAsync<TFolder>(IThirdPartyFolderStorage<TFolder> storage, int id, string folderId, string selector) where TFolder : class
|
||||
{
|
||||
var folder = _cacheFolder.Get<TFolder>($"{selector}d-" + id + "-" + folderId);
|
||||
if (folder == null)
|
||||
{
|
||||
folder = await storage.GetFolderAsync(folderId);
|
||||
if (folder != null)
|
||||
{
|
||||
_cacheFolder.Insert($"{selector}d-" + id + "-" + folderId, folder, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
internal async Task<List<TItem>> GetItemsAsync<TItem>(IThirdPartyItemStorage<TItem> storage, int id, string folderId, string selector) where TItem : class
|
||||
{
|
||||
var items = _cacheChildItems.Get<List<TItem>>($"{selector}-" + id + "-" + folderId);
|
||||
|
||||
if (items == null)
|
||||
{
|
||||
items = await storage.GetItemsAsync(folderId);
|
||||
_cacheChildItems.Insert($"{selector}-" + id + "-" + folderId, items, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
[Transient]
|
||||
public class DisposableWrapper : IDisposable
|
||||
{
|
||||
private readonly ConsumerFactory _consumerFactory;
|
||||
private readonly OAuth20TokenHelper _oAuth20TokenHelper;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ConcurrentDictionary<int, IThirdPartyStorage> _storages =
|
||||
new ConcurrentDictionary<int, IThirdPartyStorage>();
|
||||
|
||||
public DisposableWrapper(ConsumerFactory consumerFactory, IServiceProvider serviceProvider, OAuth20TokenHelper oAuth20TokenHelper)
|
||||
{
|
||||
_consumerFactory = consumerFactory;
|
||||
_serviceProvider = serviceProvider;
|
||||
_oAuth20TokenHelper = oAuth20TokenHelper;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var (key, storage) in _storages)
|
||||
{
|
||||
storage.Close();
|
||||
_storages.Remove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
internal Task<T> CreateStorageAsync<T, T1>(OAuth20Token token, int id)
|
||||
where T : IThirdPartyStorage
|
||||
where T1 : Consumer, IOAuthProvider, new()
|
||||
{
|
||||
if (TryGetStorage<T>(id, out var storage) && storage.IsOpened)
|
||||
{
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
|
||||
return InternalCreateStorageAsync<T, T1>(token, id);
|
||||
}
|
||||
|
||||
internal bool TryGetStorage<T>(int providerId, out T storage)
|
||||
{
|
||||
var result = _storages.TryGetValue(providerId, out var s);
|
||||
storage = (T)s;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool TryGetStorage(int providerId, out IThirdPartyStorage storage)
|
||||
{
|
||||
return _storages.TryGetValue(providerId, out storage);
|
||||
}
|
||||
|
||||
|
||||
private Task CheckTokenAsync<T>(OAuth20Token token, int id) where T : Consumer, IOAuthProvider, new()
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Cannot create third party session with given token");
|
||||
}
|
||||
|
||||
return InternalCheckTokenAsync<T>(token, id);
|
||||
}
|
||||
|
||||
private async Task InternalCheckTokenAsync<T>(OAuth20Token token, int id) where T : Consumer, IOAuthProvider, new()
|
||||
{
|
||||
if (token.IsExpired)
|
||||
{
|
||||
token = _oAuth20TokenHelper.RefreshToken<T>(_consumerFactory, token);
|
||||
|
||||
var dbDao = _serviceProvider.GetService<ProviderAccountDao>();
|
||||
await dbDao.UpdateProviderInfoAsync(id, new AuthData(token: token.ToJson()));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<T> InternalCreateStorageAsync<T, T1>(OAuth20Token token, int id)
|
||||
where T : IThirdPartyStorage
|
||||
where T1 : Consumer, IOAuthProvider, new()
|
||||
{
|
||||
var storage = _serviceProvider.GetService<T>();
|
||||
await CheckTokenAsync<T1>(token, id);
|
||||
|
||||
storage.Open(token);
|
||||
|
||||
_storages.TryAdd(id, storage);
|
||||
|
||||
return storage;
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@
|
||||
|
||||
namespace ASC.Files.Thirdparty.Box;
|
||||
|
||||
internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>, IDaoBase<BoxFile, BoxFolder, BoxItem>
|
||||
{
|
||||
protected override string Id => Selectors.Box.Id;
|
||||
|
||||
@ -44,7 +44,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
{
|
||||
}
|
||||
|
||||
protected static string MakeBoxId(object entryId)
|
||||
public string MakeId(object entryId)
|
||||
{
|
||||
var id = Convert.ToString(entryId, CultureInfo.InvariantCulture);
|
||||
|
||||
@ -53,14 +53,14 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
: id.TrimStart('/');
|
||||
}
|
||||
|
||||
protected static string GetParentFolderId(BoxItem boxItem)
|
||||
public string GetParentFolderId(BoxItem boxItem)
|
||||
{
|
||||
return boxItem == null || boxItem.Parent == null
|
||||
? null
|
||||
: boxItem.Parent.Id;
|
||||
}
|
||||
|
||||
protected string MakeId(BoxItem boxItem)
|
||||
public string MakeId(BoxItem boxItem)
|
||||
{
|
||||
var path = string.Empty;
|
||||
if (boxItem != null)
|
||||
@ -71,14 +71,14 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
return MakeId(path);
|
||||
}
|
||||
|
||||
protected override string MakeId(string path = null)
|
||||
public override string MakeId(string path = null)
|
||||
{
|
||||
var p = string.IsNullOrEmpty(path) || path == "0" ? "" : ("-|" + path.TrimStart('/'));
|
||||
|
||||
return $"{PathPrefix}{p}";
|
||||
}
|
||||
|
||||
protected string MakeFolderTitle(BoxFolder boxFolder)
|
||||
public string MakeFolderTitle(BoxFolder boxFolder)
|
||||
{
|
||||
if (boxFolder == null || IsRoot(boxFolder))
|
||||
{
|
||||
@ -88,7 +88,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
return Global.ReplaceInvalidCharsAndTruncate(boxFolder.Name);
|
||||
}
|
||||
|
||||
protected string MakeFileTitle(BoxFile boxFile)
|
||||
public string MakeFileTitle(BoxFile boxFile)
|
||||
{
|
||||
if (boxFile == null || string.IsNullOrEmpty(boxFile.Name))
|
||||
{
|
||||
@ -98,7 +98,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
return Global.ReplaceInvalidCharsAndTruncate(boxFile.Name);
|
||||
}
|
||||
|
||||
protected Folder<string> ToFolder(BoxFolder boxFolder)
|
||||
public Folder<string> ToFolder(BoxFolder boxFolder)
|
||||
{
|
||||
if (boxFolder == null)
|
||||
{
|
||||
@ -140,7 +140,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
return folder;
|
||||
}
|
||||
|
||||
protected static bool IsRoot(BoxFolder boxFolder)
|
||||
public static bool IsRoot(BoxFolder boxFolder)
|
||||
{
|
||||
return boxFolder.Id == "0";
|
||||
}
|
||||
@ -201,17 +201,17 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
return file;
|
||||
}
|
||||
|
||||
public async Task<Folder<string>> GetRootFolderAsync(string folderId)
|
||||
public async Task<Folder<string>> GetRootFolderAsync()
|
||||
{
|
||||
return ToFolder(await GetBoxFolderAsync("0"));
|
||||
return ToFolder(await GetFolderAsync("0"));
|
||||
}
|
||||
|
||||
protected async Task<BoxFolder> GetBoxFolderAsync(string folderId)
|
||||
public async Task<BoxFolder> GetFolderAsync(string folderId)
|
||||
{
|
||||
var boxFolderId = MakeBoxId(folderId);
|
||||
var boxFolderId = MakeId(folderId);
|
||||
try
|
||||
{
|
||||
var folder = await ProviderInfo.GetBoxFolderAsync(boxFolderId);
|
||||
var folder = await ProviderInfo.GetFolderAsync(boxFolderId);
|
||||
|
||||
return folder;
|
||||
}
|
||||
@ -221,50 +221,32 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
}
|
||||
}
|
||||
|
||||
protected ValueTask<BoxFile> GetBoxFileAsync(string fileId)
|
||||
public Task<BoxFile> GetFileAsync(string fileId)
|
||||
{
|
||||
var boxFileId = MakeBoxId(fileId);
|
||||
var boxFileId = MakeId(fileId);
|
||||
try
|
||||
{
|
||||
var file = ProviderInfo.GetBoxFileAsync(boxFileId);
|
||||
var file = ProviderInfo.GetFileAsync(boxFileId);
|
||||
|
||||
return file;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ValueTask.FromResult<BoxFile>(new ErrorFile(ex, boxFileId));
|
||||
return Task.FromResult<BoxFile>(new ErrorFile(ex, boxFileId));
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<string>> GetChildrenAsync(string folderId)
|
||||
public override async Task<IEnumerable<string>> GetChildrenAsync(string folderId)
|
||||
{
|
||||
var items = await GetBoxItemsAsync(folderId);
|
||||
var items = await GetItemsAsync(folderId);
|
||||
|
||||
return items.Select(entry => MakeId(entry.Id));
|
||||
}
|
||||
|
||||
protected List<BoxItem> GetBoxItems(string parentId, bool? folder = null)
|
||||
public async Task<List<BoxItem>> GetItemsAsync(string parentId, bool? folder = null)
|
||||
{
|
||||
var boxFolderId = MakeBoxId(parentId);
|
||||
var items = ProviderInfo.GetBoxItemsAsync(boxFolderId).Result;
|
||||
|
||||
if (folder.HasValue)
|
||||
{
|
||||
if (folder.Value)
|
||||
{
|
||||
return items.Where(i => i is BoxFolder).ToList();
|
||||
}
|
||||
|
||||
return items.Where(i => i is BoxFile).ToList();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
protected async Task<List<BoxItem>> GetBoxItemsAsync(string parentId, bool? folder = null)
|
||||
{
|
||||
var boxFolderId = MakeBoxId(parentId);
|
||||
var items = await ProviderInfo.GetBoxItemsAsync(boxFolderId);
|
||||
var boxFolderId = MakeId(parentId);
|
||||
var items = await ProviderInfo.GetItemsAsync(boxFolderId);
|
||||
|
||||
if (folder.HasValue)
|
||||
{
|
||||
@ -309,36 +291,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
}
|
||||
}
|
||||
|
||||
protected string GetAvailableTitle(string requestTitle, string parentFolderId, Func<string, string, bool> isExist)
|
||||
{
|
||||
if (!isExist(requestTitle, parentFolderId))
|
||||
{
|
||||
return requestTitle;
|
||||
}
|
||||
|
||||
var re = new Regex(@"( \(((?<index>[0-9])+)\)(\.[^\.]*)?)$");
|
||||
var match = re.Match(requestTitle);
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
var insertIndex = requestTitle.Length;
|
||||
if (requestTitle.LastIndexOf('.') != -1)
|
||||
{
|
||||
insertIndex = requestTitle.LastIndexOf('.');
|
||||
}
|
||||
|
||||
requestTitle = requestTitle.Insert(insertIndex, " (1)");
|
||||
}
|
||||
|
||||
while (isExist(requestTitle, parentFolderId))
|
||||
{
|
||||
requestTitle = re.Replace(requestTitle, MatchEvaluator);
|
||||
}
|
||||
|
||||
return requestTitle;
|
||||
}
|
||||
|
||||
protected async Task<string> GetAvailableTitleAsync(string requestTitle, string parentFolderId, Func<string, string, Task<bool>> isExist)
|
||||
public async Task<string> GetAvailableTitleAsync(string requestTitle, string parentFolderId, Func<string, string, Task<bool>> isExist)
|
||||
{
|
||||
if (!await isExist(requestTitle, parentFolderId))
|
||||
{
|
||||
|
@ -463,7 +463,7 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
|
||||
throw new Exception(errorFile.Error);
|
||||
}
|
||||
|
||||
var toBoxFolder = await GetBoxFolderAsync(toFolderId);
|
||||
var toBoxFolder = await GetFolderAsync(toFolderId);
|
||||
if (toBoxFolder is ErrorFolder errorFolder)
|
||||
{
|
||||
throw new Exception(errorFolder.Error);
|
||||
@ -505,7 +505,7 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
|
||||
throw new Exception(errorFile.Error);
|
||||
}
|
||||
|
||||
var toBoxFolder = await GetBoxFolderAsync(toFolderId);
|
||||
var toBoxFolder = await GetFolderAsync(toFolderId);
|
||||
if (toBoxFolder is ErrorFolder errorFolder)
|
||||
{
|
||||
throw new Exception(errorFolder.Error);
|
||||
|
@ -62,7 +62,7 @@ internal class BoxFolderDao : BoxDaoBase, IFolderDao<string>
|
||||
|
||||
public async Task<Folder<string>> GetFolderAsync(string folderId)
|
||||
{
|
||||
return ToFolder(await GetBoxFolderAsync(folderId));
|
||||
return ToFolder(await base.GetFolderAsync(folderId));
|
||||
}
|
||||
|
||||
public async Task<Folder<string>> GetFolderAsync(string title, string parentId)
|
||||
@ -178,7 +178,7 @@ internal class BoxFolderDao : BoxDaoBase, IFolderDao<string>
|
||||
|
||||
while (folderId != null)
|
||||
{
|
||||
var boxFolder = await GetBoxFolderAsync(folderId);
|
||||
var boxFolder = await base.GetFolderAsync(folderId);
|
||||
|
||||
if (boxFolder is ErrorFolder)
|
||||
{
|
||||
@ -246,7 +246,7 @@ internal class BoxFolderDao : BoxDaoBase, IFolderDao<string>
|
||||
|
||||
public async Task DeleteFolderAsync(string folderId)
|
||||
{
|
||||
var boxFolder = await GetBoxFolderAsync(folderId);
|
||||
var boxFolder = await base.GetFolderAsync(folderId);
|
||||
var id = MakeId(boxFolder);
|
||||
|
||||
using var filesDbContext = _dbContextFactory.CreateDbContext();
|
||||
@ -310,13 +310,13 @@ internal class BoxFolderDao : BoxDaoBase, IFolderDao<string>
|
||||
|
||||
public async Task<string> MoveFolderAsync(string folderId, string toFolderId, CancellationToken? cancellationToken)
|
||||
{
|
||||
var boxFolder = await GetBoxFolderAsync(folderId);
|
||||
var boxFolder = await base.GetFolderAsync(folderId);
|
||||
if (boxFolder is ErrorFolder errorFolder)
|
||||
{
|
||||
throw new Exception(errorFolder.Error);
|
||||
}
|
||||
|
||||
var toBoxFolder = await GetBoxFolderAsync(toFolderId);
|
||||
var toBoxFolder = await base.GetFolderAsync(toFolderId);
|
||||
if (toBoxFolder is ErrorFolder errorFolder1)
|
||||
{
|
||||
throw new Exception(errorFolder1.Error);
|
||||
@ -378,13 +378,13 @@ internal class BoxFolderDao : BoxDaoBase, IFolderDao<string>
|
||||
|
||||
public async Task<Folder<string>> CopyFolderAsync(string folderId, string toFolderId, CancellationToken? cancellationToken)
|
||||
{
|
||||
var boxFolder = await GetBoxFolderAsync(folderId);
|
||||
var boxFolder = await base.GetFolderAsync(folderId);
|
||||
if (boxFolder is ErrorFolder errorFolder)
|
||||
{
|
||||
throw new Exception(errorFolder.Error);
|
||||
}
|
||||
|
||||
var toBoxFolder = await GetBoxFolderAsync(toFolderId);
|
||||
var toBoxFolder = await base.GetFolderAsync(toFolderId);
|
||||
if (toBoxFolder is ErrorFolder errorFolder1)
|
||||
{
|
||||
throw new Exception(errorFolder1.Error);
|
||||
@ -439,7 +439,7 @@ internal class BoxFolderDao : BoxDaoBase, IFolderDao<string>
|
||||
|
||||
public async Task<string> RenameFolderAsync(Folder<string> folder, string newTitle)
|
||||
{
|
||||
var boxFolder = await GetBoxFolderAsync(folder.Id);
|
||||
var boxFolder = await base.GetFolderAsync(folder.Id);
|
||||
var parentFolderId = GetParentFolderId(boxFolder);
|
||||
|
||||
if (IsRoot(boxFolder))
|
||||
|
@ -28,328 +28,11 @@ namespace ASC.Files.Thirdparty.Box;
|
||||
|
||||
[Transient]
|
||||
[DebuggerDisplay("{CustomerTitle}")]
|
||||
internal class BoxProviderInfo : IProviderInfo
|
||||
internal class BoxProviderInfo : AbstractProviderInfo<BoxFile, BoxFolder, BoxItem, BoxLoginProvider>
|
||||
{
|
||||
private readonly BoxProviderInfoHelper _boxProviderInfoHelper;
|
||||
private readonly BoxStorageDisposableWrapper _wrapper;
|
||||
private string _rootId;
|
||||
internal override string Selector { get; } = Selectors.Box.Id;
|
||||
|
||||
public BoxProviderInfo(
|
||||
BoxStorageDisposableWrapper wrapper,
|
||||
BoxProviderInfoHelper boxProviderInfoHelper)
|
||||
public BoxProviderInfo(DisposableWrapper wrapper) : base(wrapper)
|
||||
{
|
||||
_wrapper = wrapper;
|
||||
_boxProviderInfoHelper = boxProviderInfoHelper;
|
||||
}
|
||||
|
||||
public string BoxRootId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_rootId))
|
||||
{
|
||||
var storage = StorageAsync.Result;
|
||||
_rootId = storage.GetRootFolderIdAsync().Result;
|
||||
}
|
||||
|
||||
return _rootId;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime CreateOn { get; set; }
|
||||
public string CustomerTitle { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
public FolderType FolderType { get; set; }
|
||||
public bool HasLogo { get; set; }
|
||||
public int ID { get; set; }
|
||||
public Guid Owner { get; set; }
|
||||
public bool Private { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
public string RootFolderId => $"{Selectors.Box.Id}-" + ID;
|
||||
public FolderType RootFolderType { get; set; }
|
||||
public OAuth20Token Token { get; set; }
|
||||
internal bool StorageOpened => _wrapper.TryGetStorage(ID, out var storage) && storage.IsOpened;
|
||||
|
||||
internal Task<BoxStorage> StorageAsync
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_wrapper.TryGetStorage(ID, out var storage) || !storage.IsOpened)
|
||||
{
|
||||
return _wrapper.CreateStorageAsync(Token, ID);
|
||||
}
|
||||
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> CheckAccessAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Task.FromResult(!string.IsNullOrEmpty(BoxRootId));
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (StorageOpened)
|
||||
{
|
||||
StorageAsync.Result.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public Task InvalidateStorageAsync()
|
||||
{
|
||||
if (_wrapper != null)
|
||||
{
|
||||
_wrapper.Dispose();
|
||||
}
|
||||
|
||||
return CacheResetAsync();
|
||||
}
|
||||
|
||||
public void UpdateTitle(string newtitle)
|
||||
{
|
||||
CustomerTitle = newtitle;
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(BoxItem boxItem)
|
||||
{
|
||||
return _boxProviderInfoHelper.CacheResetAsync(ID, boxItem);
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(string boxPath = null, bool? isFile = null)
|
||||
{
|
||||
return _boxProviderInfoHelper.CacheResetAsync(BoxRootId, ID, boxPath, isFile);
|
||||
}
|
||||
|
||||
internal async ValueTask<BoxFile> GetBoxFileAsync(string dropboxFilePath)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _boxProviderInfoHelper.GetBoxFileAsync(storage, ID, dropboxFilePath);
|
||||
}
|
||||
|
||||
internal async Task<BoxFolder> GetBoxFolderAsync(string dropboxFolderPath)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _boxProviderInfoHelper.GetBoxFolderAsync(storage, ID, dropboxFolderPath);
|
||||
}
|
||||
|
||||
internal async Task<List<BoxItem>> GetBoxItemsAsync(string dropboxFolderPath)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _boxProviderInfoHelper.GetBoxItemsAsync(storage, ID, dropboxFolderPath);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(string boxFileId, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _boxProviderInfoHelper.GetThumbnailAsync(storage, boxFileId, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Transient]
|
||||
internal class BoxStorageDisposableWrapper : IDisposable
|
||||
{
|
||||
private readonly ConsumerFactory _consumerFactory;
|
||||
private readonly OAuth20TokenHelper _oAuth20TokenHelper;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly TempStream _tempStream;
|
||||
private readonly ConcurrentDictionary<int, BoxStorage> _storages =
|
||||
new ConcurrentDictionary<int, BoxStorage>();
|
||||
|
||||
public BoxStorageDisposableWrapper(ConsumerFactory consumerFactory, TempStream tempStream, IServiceProvider serviceProvider, OAuth20TokenHelper oAuth20TokenHelper)
|
||||
{
|
||||
_consumerFactory = consumerFactory;
|
||||
_tempStream = tempStream;
|
||||
_serviceProvider = serviceProvider;
|
||||
_oAuth20TokenHelper = oAuth20TokenHelper;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var (key, storage) in _storages)
|
||||
{
|
||||
storage.Close();
|
||||
_storages.Remove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
internal Task<BoxStorage> CreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (TryGetStorage(id, out var storage) && storage.IsOpened)
|
||||
{
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
|
||||
return InternalCreateStorageAsync(token, id);
|
||||
}
|
||||
|
||||
internal bool TryGetStorage(int providerId, out BoxStorage storage)
|
||||
{
|
||||
return _storages.TryGetValue(providerId, out storage);
|
||||
}
|
||||
|
||||
private Task CheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Cannot create Box session with given token");
|
||||
}
|
||||
|
||||
return InternalCheckTokenAsync(token, id);
|
||||
}
|
||||
|
||||
private async Task InternalCheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token.IsExpired)
|
||||
{
|
||||
token = _oAuth20TokenHelper.RefreshToken<BoxLoginProvider>(_consumerFactory, token);
|
||||
|
||||
var dbDao = _serviceProvider.GetService<ProviderAccountDao>();
|
||||
await dbDao.UpdateProviderInfoAsync(id, new AuthData(token: token.ToJson()));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<BoxStorage> InternalCreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
var boxStorage = new BoxStorage(_tempStream);
|
||||
await CheckTokenAsync(token, id);
|
||||
|
||||
boxStorage.Open(token);
|
||||
|
||||
_storages.TryAdd(id, boxStorage);
|
||||
|
||||
return boxStorage;
|
||||
}
|
||||
}
|
||||
|
||||
[Singletone]
|
||||
public class BoxProviderInfoHelper
|
||||
{
|
||||
private readonly ICache _cacheChildItems;
|
||||
private readonly TimeSpan _cacheExpiration = TimeSpan.FromMinutes(1);
|
||||
private readonly ICache _cacheFile;
|
||||
private readonly ICache _cacheFolder;
|
||||
private readonly ICacheNotify<BoxCacheItem> _cacheNotify;
|
||||
|
||||
public BoxProviderInfoHelper(ICacheNotify<BoxCacheItem> cacheNotify, ICache cache)
|
||||
{
|
||||
_cacheFile = cache;
|
||||
_cacheFolder = cache;
|
||||
_cacheChildItems = cache;
|
||||
_cacheNotify = cacheNotify;
|
||||
_cacheNotify.Subscribe((i) =>
|
||||
{
|
||||
if (i.ResetAll)
|
||||
{
|
||||
_cacheChildItems.Remove(new Regex($"^{Selectors.Box.Id}-" + i.Key + ".*"));
|
||||
_cacheFile.Remove(new Regex($"^{Selectors.Box.Id}f-" + i.Key + ".*"));
|
||||
_cacheFolder.Remove(new Regex($"^{Selectors.Box.Id}d-" + i.Key + ".*"));
|
||||
}
|
||||
|
||||
if (!i.IsFileExists)
|
||||
{
|
||||
_cacheChildItems.Remove($"{Selectors.Box.Id}-" + i.Key);
|
||||
|
||||
_cacheFolder.Remove($"{Selectors.Box.Id}d-" + i.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i.IsFileExists)
|
||||
{
|
||||
_cacheFile.Remove($"{Selectors.Box.Id}f-" + i.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cacheFolder.Remove($"{Selectors.Box.Id}d-" + i.Key);
|
||||
}
|
||||
}
|
||||
}, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(int id, BoxItem boxItem)
|
||||
{
|
||||
if (boxItem != null)
|
||||
{
|
||||
await _cacheNotify.PublishAsync(new BoxCacheItem { IsFile = boxItem is BoxFile, Key = id + "-" + boxItem.Id }, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(string boxRootId, int id, string boxId = null, bool? isFile = null)
|
||||
{
|
||||
var key = id + "-";
|
||||
if (boxId == null)
|
||||
{
|
||||
await _cacheNotify.PublishAsync(new BoxCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (boxId == boxRootId)
|
||||
{
|
||||
boxId = "0";
|
||||
}
|
||||
|
||||
key += boxId;
|
||||
|
||||
await _cacheNotify.PublishAsync(new BoxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal async ValueTask<BoxFile> GetBoxFileAsync(BoxStorage storage, int id, string boxFileId)
|
||||
{
|
||||
var file = _cacheFile.Get<BoxFile>($"{Selectors.Box.Id}f-" + id + "-" + boxFileId);
|
||||
if (file == null)
|
||||
{
|
||||
file = await storage.GetFileAsync(boxFileId);
|
||||
if (file != null)
|
||||
{
|
||||
_cacheFile.Insert($"{Selectors.Box.Id}f-" + id + "-" + boxFileId, file, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
internal async Task<BoxFolder> GetBoxFolderAsync(BoxStorage storage, int id, string boxFolderId)
|
||||
{
|
||||
var folder = _cacheFolder.Get<BoxFolder>($"{Selectors.Box.Id}d-" + id + "-" + boxFolderId);
|
||||
if (folder == null)
|
||||
{
|
||||
folder = await storage.GetFolderAsync(boxFolderId);
|
||||
if (folder != null)
|
||||
{
|
||||
_cacheFolder.Insert($"{Selectors.Box.Id}d-" + id + "-" + boxFolderId, folder, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
internal async Task<List<BoxItem>> GetBoxItemsAsync(BoxStorage storage, int id, string boxFolderId)
|
||||
{
|
||||
var items = _cacheChildItems.Get<List<BoxItem>>($"{Selectors.Box.Id}-" + id + "-" + boxFolderId);
|
||||
|
||||
if (items == null)
|
||||
{
|
||||
items = await storage.GetItemsAsync(boxFolderId);
|
||||
_cacheChildItems.Insert($"{Selectors.Box.Id}-" + id + "-" + boxFolderId, items, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(BoxStorage storage, string boxFileId, int width, int height)
|
||||
{
|
||||
return await storage.GetThumbnailAsync(boxFileId, width, height);
|
||||
}
|
||||
}
|
@ -24,11 +24,13 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
using BoxSDK = Box.V2;
|
||||
|
||||
namespace ASC.Files.Thirdparty.Box;
|
||||
|
||||
internal class BoxStorage
|
||||
internal class BoxStorage : IThirdPartyStorage<BoxFile, BoxFolder, BoxItem>
|
||||
{
|
||||
private BoxClient _boxClient;
|
||||
|
||||
@ -37,7 +39,7 @@ internal class BoxStorage
|
||||
public bool IsOpened { get; private set; }
|
||||
private readonly TempStream _tempStream;
|
||||
|
||||
public long MaxChunkedUploadFileSize = 250L * 1024L * 1024L;
|
||||
private readonly long _maxChunkedUploadFileSize = 250L * 1024L * 1024L;
|
||||
|
||||
public BoxStorage(TempStream tempStream)
|
||||
{
|
||||
@ -63,13 +65,6 @@ internal class BoxStorage
|
||||
IsOpened = false;
|
||||
}
|
||||
|
||||
public async Task<string> GetRootFolderIdAsync()
|
||||
{
|
||||
var root = await GetFolderAsync("0");
|
||||
|
||||
return root.Id;
|
||||
}
|
||||
|
||||
public async Task<BoxFolder> GetFolderAsync(string folderId)
|
||||
{
|
||||
try
|
||||
@ -87,25 +82,38 @@ internal class BoxStorage
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<BoxFile> GetFileAsync(string fileId)
|
||||
public async Task<bool> CheckAccessAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new ValueTask<BoxFile>(_boxClient.FilesManager.GetInformationAsync(fileId, _boxFields));
|
||||
var rootFolder = await GetFolderAsync("0");
|
||||
return !string.IsNullOrEmpty(rootFolder.Id);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<BoxFile> GetFileAsync(string fileId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _boxClient.FilesManager.GetInformationAsync(fileId, _boxFields);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex.InnerException is BoxSDK.Exceptions.BoxAPIException boxException && boxException.Error.Status == ((int)HttpStatusCode.NotFound).ToString())
|
||||
{
|
||||
return ValueTask.FromResult<BoxFile>(null);
|
||||
return Task.FromResult<BoxFile>(null);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<BoxItem>> GetItemsAsync(string folderId, int limit = 500)
|
||||
public async Task<List<BoxItem>> GetItemsAsync(string folderId)
|
||||
{
|
||||
var folderItems = await _boxClient.FoldersManager.GetFolderItemsAsync(folderId, limit, 0, _boxFields);
|
||||
var folderItems = await _boxClient.FoldersManager.GetFolderItemsAsync(folderId, 500, 0, _boxFields);
|
||||
|
||||
return folderItems.Entries;
|
||||
}
|
||||
@ -117,7 +125,7 @@ internal class BoxStorage
|
||||
return InternalDownloadStreamAsync(file, offset);
|
||||
}
|
||||
|
||||
public async Task<Stream> InternalDownloadStreamAsync(BoxFile file, int offset = 0)
|
||||
private async Task<Stream> InternalDownloadStreamAsync(BoxFile file, int offset = 0)
|
||||
{
|
||||
if (offset > 0 && file.Size.HasValue)
|
||||
{
|
||||
@ -265,15 +273,14 @@ internal class BoxStorage
|
||||
public async Task<long> GetMaxUploadSizeAsync()
|
||||
{
|
||||
var boxUser = await _boxClient.UsersManager.GetCurrentUserInformationAsync(new List<string>() { "max_upload_size" });
|
||||
var max = boxUser.MaxUploadSize ?? MaxChunkedUploadFileSize;
|
||||
var max = boxUser.MaxUploadSize ?? _maxChunkedUploadFileSize;
|
||||
|
||||
//todo: without chunked uploader:
|
||||
return Math.Min(max, MaxChunkedUploadFileSize);
|
||||
return Math.Min(max, _maxChunkedUploadFileSize);
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
|
||||
var boxRepresentation = new BoxRepresentationRequest();
|
||||
boxRepresentation.FileId = fileId;
|
||||
boxRepresentation.XRepHints = $"[jpg?dimensions=320x320]";
|
||||
|
@ -26,315 +26,13 @@
|
||||
|
||||
namespace ASC.Files.Thirdparty.Dropbox;
|
||||
|
||||
[Singletone]
|
||||
public class DropboxProviderInfoHelper
|
||||
{
|
||||
private readonly ICache _cacheChildItems;
|
||||
private readonly TimeSpan _cacheExpiration;
|
||||
private readonly ICache _cacheFile;
|
||||
private readonly ICache _cacheFolder;
|
||||
private readonly ICacheNotify<DropboxCacheItem> _cacheNotify;
|
||||
|
||||
public DropboxProviderInfoHelper(ICacheNotify<DropboxCacheItem> cacheNotify, ICache cache)
|
||||
{
|
||||
_cacheExpiration = TimeSpan.FromMinutes(1);
|
||||
_cacheFile = cache;
|
||||
_cacheFolder = cache;
|
||||
_cacheChildItems = cache;
|
||||
_cacheNotify = cacheNotify;
|
||||
|
||||
_cacheNotify.Subscribe((i) =>
|
||||
{
|
||||
if (i.ResetAll)
|
||||
{
|
||||
_cacheFile.Remove(new Regex($"^{Selectors.Dropbox.Id}f-" + i.Key + ".*"));
|
||||
_cacheFolder.Remove(new Regex($"^{Selectors.Dropbox.Id}d-" + i.Key + ".*"));
|
||||
_cacheChildItems.Remove(new Regex($"^{Selectors.Dropbox.Id}-" + i.Key + ".*"));
|
||||
}
|
||||
|
||||
if (!i.IsFileExists)
|
||||
{
|
||||
_cacheChildItems.Remove($"{Selectors.Dropbox.Id}-" + i.Key);
|
||||
|
||||
_cacheFolder.Remove($"{Selectors.Dropbox.Id}d-" + i.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i.IsFileExists)
|
||||
{
|
||||
_cacheFile.Remove($"{Selectors.Dropbox.Id}f-" + i.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cacheFolder.Remove($"{Selectors.Dropbox.Id}d-" + i.Key);
|
||||
}
|
||||
}
|
||||
}, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(int id, Metadata dropboxItem)
|
||||
{
|
||||
if (dropboxItem != null)
|
||||
{
|
||||
await _cacheNotify.PublishAsync(new DropboxCacheItem { IsFile = dropboxItem.AsFolder != null, Key = id + "-" + dropboxItem.PathDisplay }, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(int id, string dropboxPath = null, bool? isFile = null)
|
||||
{
|
||||
var key = id + "-";
|
||||
if (dropboxPath == null)
|
||||
{
|
||||
await _cacheNotify.PublishAsync(new DropboxCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove);
|
||||
}
|
||||
else
|
||||
{
|
||||
key += dropboxPath;
|
||||
|
||||
await _cacheNotify.PublishAsync(new DropboxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal async ValueTask<FileMetadata> GetDropboxFileAsync(DropboxStorage storage, int id, string dropboxFilePath)
|
||||
{
|
||||
var file = _cacheFile.Get<FileMetadata>($"{Selectors.Dropbox.Id}f-" + id + "-" + dropboxFilePath);
|
||||
if (file == null)
|
||||
{
|
||||
file = await storage.GetFileAsync(dropboxFilePath);
|
||||
if (file != null)
|
||||
{
|
||||
_cacheFile.Insert($"{Selectors.Dropbox.Id}f-" + id + "-" + dropboxFilePath, file, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
internal async Task<FolderMetadata> GetDropboxFolderAsync(DropboxStorage storage, int id, string dropboxFolderPath)
|
||||
{
|
||||
var folder = _cacheFolder.Get<FolderMetadata>($"{Selectors.Dropbox.Id}d-" + id + "-" + dropboxFolderPath);
|
||||
if (folder == null)
|
||||
{
|
||||
folder = await storage.GetFolderAsync(dropboxFolderPath);
|
||||
if (folder != null)
|
||||
{
|
||||
_cacheFolder.Insert($"{Selectors.Dropbox.Id}d-" + id + "-" + dropboxFolderPath, folder, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return folder;
|
||||
}
|
||||
internal async Task<List<Metadata>> GetDropboxItemsAsync(DropboxStorage storage, int id, string dropboxFolderPath)
|
||||
{
|
||||
var items = _cacheChildItems.Get<List<Metadata>>($"{Selectors.Dropbox.Id}-" + id + "-" + dropboxFolderPath);
|
||||
|
||||
if (items == null)
|
||||
{
|
||||
items = await storage.GetItemsAsync(dropboxFolderPath);
|
||||
_cacheChildItems.Insert($"{Selectors.Dropbox.Id}-" + id + "-" + dropboxFolderPath, items, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
internal Task<Stream> GetThumbnailsAsync(DropboxStorage storage, string filePath, int width, int height)
|
||||
{
|
||||
return storage.GetThumbnailsAsync(filePath, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Transient]
|
||||
[DebuggerDisplay("{CustomerTitle}")]
|
||||
internal class DropboxProviderInfo : IProviderInfo
|
||||
internal class DropboxProviderInfo : AbstractProviderInfo<FileMetadata, FolderMetadata, Metadata, DropboxLoginProvider>
|
||||
{
|
||||
private readonly DropboxProviderInfoHelper _dropboxProviderInfoHelper;
|
||||
private readonly DropboxStorageDisposableWrapper _wrapper;
|
||||
internal override string Selector { get; } = Selectors.Dropbox.Id;
|
||||
|
||||
public DropboxProviderInfo(
|
||||
DropboxStorageDisposableWrapper wrapper,
|
||||
DropboxProviderInfoHelper dropboxProviderInfoHelper
|
||||
)
|
||||
public DropboxProviderInfo(DisposableWrapper wrapper) : base(wrapper)
|
||||
{
|
||||
_wrapper = wrapper;
|
||||
_dropboxProviderInfoHelper = dropboxProviderInfoHelper;
|
||||
}
|
||||
|
||||
public DateTime CreateOn { get; set; }
|
||||
public string CustomerTitle { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
public FolderType FolderType { get; set; }
|
||||
public bool HasLogo { get; set; }
|
||||
public int ID { get; set; }
|
||||
public Guid Owner { get; set; }
|
||||
public bool Private { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
public string RootFolderId => $"{Selectors.Dropbox.Id}-" + ID;
|
||||
public FolderType RootFolderType { get; set; }
|
||||
public OAuth20Token Token { get; set; }
|
||||
internal bool StorageOpened => _wrapper.TryGetStorage(ID, out var storage) && storage.IsOpened;
|
||||
|
||||
internal Task<DropboxStorage> StorageAsync
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_wrapper.TryGetStorage(ID, out var storage) || !storage.IsOpened)
|
||||
{
|
||||
return _wrapper.CreateStorageAsync(Token, ID);
|
||||
}
|
||||
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> CheckAccessAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await (await StorageAsync).GetUsedSpaceAsync();
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (StorageOpened)
|
||||
{
|
||||
StorageAsync.Result.Close();
|
||||
}
|
||||
}
|
||||
public Task InvalidateStorageAsync()
|
||||
{
|
||||
if (_wrapper != null)
|
||||
{
|
||||
_wrapper.Dispose();
|
||||
}
|
||||
|
||||
return CacheResetAsync();
|
||||
}
|
||||
|
||||
public void UpdateTitle(string newtitle)
|
||||
{
|
||||
CustomerTitle = newtitle;
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(Metadata dropboxItem)
|
||||
{
|
||||
return _dropboxProviderInfoHelper.CacheResetAsync(ID, dropboxItem);
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(string dropboxPath = null, bool? isFile = null)
|
||||
{
|
||||
return _dropboxProviderInfoHelper.CacheResetAsync(ID, dropboxPath, isFile);
|
||||
}
|
||||
|
||||
internal async Task<FileMetadata> GetDropboxFileAsync(string dropboxFilePath)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _dropboxProviderInfoHelper.GetDropboxFileAsync(storage, ID, dropboxFilePath);
|
||||
}
|
||||
|
||||
internal async Task<FolderMetadata> GetDropboxFolderAsync(string dropboxFolderPath)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _dropboxProviderInfoHelper.GetDropboxFolderAsync(storage, ID, dropboxFolderPath);
|
||||
}
|
||||
|
||||
internal async Task<List<Metadata>> GetDropboxItemsAsync(string dropboxFolderPath)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _dropboxProviderInfoHelper.GetDropboxItemsAsync(storage, ID, dropboxFolderPath);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailsAsync(string filePath, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _dropboxProviderInfoHelper.GetThumbnailsAsync(storage, filePath, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Transient(Additional = typeof(DropboxStorageDisposableWrapperExtention))]
|
||||
internal class DropboxStorageDisposableWrapper : IDisposable
|
||||
{
|
||||
private readonly ConsumerFactory _consumerFactory;
|
||||
private readonly OAuth20TokenHelper _oAuth20TokenHelper;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ConcurrentDictionary<int, DropboxStorage> _storages =
|
||||
new ConcurrentDictionary<int, DropboxStorage>();
|
||||
|
||||
public DropboxStorageDisposableWrapper(IServiceProvider serviceProvider, OAuth20TokenHelper oAuth20TokenHelper, ConsumerFactory consumerFactory)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_oAuth20TokenHelper = oAuth20TokenHelper;
|
||||
_consumerFactory = consumerFactory;
|
||||
}
|
||||
|
||||
public Task<DropboxStorage> CreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (TryGetStorage(id, out var storage) && storage.IsOpened)
|
||||
{
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
|
||||
return InternalCreateStorageAsync(token, id);
|
||||
}
|
||||
|
||||
public bool TryGetStorage(int id, out DropboxStorage storage)
|
||||
{
|
||||
return _storages.TryGetValue(id, out storage);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var (key, storage) in _storages)
|
||||
{
|
||||
storage.Close();
|
||||
_storages.Remove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DropboxStorage> InternalCreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
var dropboxStorage = _serviceProvider.GetRequiredService<DropboxStorage>();
|
||||
|
||||
await CheckTokenAsync(token, id);
|
||||
|
||||
dropboxStorage.Open(token);
|
||||
|
||||
_storages.TryAdd(id, dropboxStorage);
|
||||
|
||||
return dropboxStorage;
|
||||
}
|
||||
|
||||
private Task CheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Cannot create Dropbox session with given token");
|
||||
}
|
||||
|
||||
return InternalCheckTokenAsync(token, id);
|
||||
}
|
||||
|
||||
private async Task InternalCheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token.IsExpired)
|
||||
{
|
||||
token = _oAuth20TokenHelper.RefreshToken<DropboxLoginProvider>(_consumerFactory, token);
|
||||
var dbDao = _serviceProvider.GetService<ProviderAccountDao>();
|
||||
var authData = new AuthData(token: token.ToJson());
|
||||
await dbDao.UpdateProviderInfoAsync(id, authData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DropboxStorageDisposableWrapperExtention
|
||||
{
|
||||
public static void Register(DIHelper dIHelper)
|
||||
{
|
||||
dIHelper.TryAdd<DropboxStorage>();
|
||||
}
|
||||
}
|
@ -24,12 +24,14 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using Google.Api.Gax.ResourceNames;
|
||||
|
||||
using ThumbnailSize = Dropbox.Api.Files.ThumbnailSize;
|
||||
|
||||
namespace ASC.Files.Thirdparty.Dropbox;
|
||||
|
||||
[Transient]
|
||||
internal class DropboxStorage : IDisposable
|
||||
internal class DropboxStorage : IThirdPartyStorage<FileMetadata, FolderMetadata, Metadata>, IDisposable
|
||||
{
|
||||
public bool IsOpened { get; private set; }
|
||||
public long MaxChunkedUploadFileSize = 20L * 1024L * 1024L * 1024L;
|
||||
@ -68,11 +70,17 @@ internal class DropboxStorage : IDisposable
|
||||
return (parentPath ?? "") + "/" + (name ?? "");
|
||||
}
|
||||
|
||||
public async Task<long> GetUsedSpaceAsync()
|
||||
public async Task<bool> CheckAccessAsync()
|
||||
{
|
||||
var spaceUsage = await _dropboxClient.Users.GetSpaceUsageAsync();
|
||||
|
||||
return (long)spaceUsage.Used;
|
||||
try
|
||||
{
|
||||
await _dropboxClient.Users.GetSpaceUsageAsync();
|
||||
return true;
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -86,7 +94,7 @@ internal class DropboxStorage : IDisposable
|
||||
return InternalGetFolderAsync(folderPath);
|
||||
}
|
||||
|
||||
public async Task<FolderMetadata> InternalGetFolderAsync(string folderPath)
|
||||
private async Task<FolderMetadata> InternalGetFolderAsync(string folderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -105,17 +113,17 @@ internal class DropboxStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<FileMetadata> GetFileAsync(string filePath)
|
||||
public Task<FileMetadata> GetFileAsync(string filePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filePath) || filePath == "/")
|
||||
{
|
||||
return ValueTask.FromResult<FileMetadata>(null);
|
||||
return Task.FromResult<FileMetadata>(null);
|
||||
}
|
||||
|
||||
return InternalGetFileAsync(filePath);
|
||||
}
|
||||
|
||||
private async ValueTask<FileMetadata> InternalGetFileAsync(string filePath)
|
||||
private async Task<FileMetadata> InternalGetFileAsync(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -141,7 +149,7 @@ internal class DropboxStorage : IDisposable
|
||||
return new List<Metadata>(data.Entries);
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnailsAsync(string filePath, int width, int height)
|
||||
public async Task<Stream> GetThumbnailAsync(string filePath, int width, int height)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -170,14 +178,15 @@ internal class DropboxStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public Task<Stream> DownloadStreamAsync(string filePath, int offset = 0)
|
||||
public Task<Stream> DownloadStreamAsync(FileMetadata file, int offset = 0)
|
||||
{
|
||||
var filePath = MakeId(file);
|
||||
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(filePath);
|
||||
|
||||
return InternalDownloadStreamAsync(filePath, offset);
|
||||
}
|
||||
|
||||
public async Task<Stream> InternalDownloadStreamAsync(string filePath, int offset = 0)
|
||||
private async Task<Stream> InternalDownloadStreamAsync(string filePath, int offset = 0)
|
||||
{
|
||||
using var response = await _dropboxClient.Files.DownloadAsync(filePath);
|
||||
var tempBuffer = _tempStream.Create();
|
||||
@ -222,6 +231,15 @@ internal class DropboxStorage : IDisposable
|
||||
return (FolderMetadata)result.Metadata;
|
||||
}
|
||||
|
||||
public async Task<FolderMetadata> RenameFolderAsync(string dropboxFolderPath, string folderName)
|
||||
{
|
||||
var folder = await GetFolderAsync(dropboxFolderPath);
|
||||
var pathTo = GetParentFolderId(folder);
|
||||
var result = await _dropboxClient.Files.MoveV2Async(dropboxFolderPath, MakeDropboxPath(pathTo, folderName), autorename: true);
|
||||
|
||||
return (FolderMetadata)result.Metadata;
|
||||
}
|
||||
|
||||
public async Task<FileMetadata> MoveFileAsync(string dropboxFilePath, string dropboxFolderPathTo, string fileName)
|
||||
{
|
||||
var pathTo = MakeDropboxPath(dropboxFolderPathTo, fileName);
|
||||
@ -230,6 +248,15 @@ internal class DropboxStorage : IDisposable
|
||||
return (FileMetadata)result.Metadata;
|
||||
}
|
||||
|
||||
public async Task<FileMetadata> RenameFileAsync(string dropboxFilePath, string fileName)
|
||||
{
|
||||
var file = await GetFileAsync(dropboxFilePath);
|
||||
var pathTo = GetParentFolderId(file);
|
||||
var result = await _dropboxClient.Files.MoveV2Async(dropboxFilePath, MakeDropboxPath(pathTo, fileName), autorename: true);
|
||||
|
||||
return (FileMetadata)result.Metadata;
|
||||
}
|
||||
|
||||
public async Task<FolderMetadata> CopyFolderAsync(string dropboxFolderPath, string dropboxFolderPathTo, string folderName)
|
||||
{
|
||||
var pathTo = MakeDropboxPath(dropboxFolderPathTo, folderName);
|
||||
@ -278,6 +305,40 @@ internal class DropboxStorage : IDisposable
|
||||
new CommitInfo(dropboxFilePath, WriteMode.Overwrite.Instance));
|
||||
}
|
||||
|
||||
public string MakeId(Metadata dropboxItem)
|
||||
{
|
||||
string path = null;
|
||||
if (dropboxItem != null)
|
||||
{
|
||||
path = dropboxItem.PathDisplay;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public string GetParentFolderId(Metadata dropboxItem)
|
||||
{
|
||||
if (dropboxItem == null || IsRoot(dropboxItem.AsFolder))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var pathLength = dropboxItem.PathDisplay.Length - dropboxItem.Name.Length;
|
||||
|
||||
return dropboxItem.PathDisplay.Substring(0, pathLength > 1 ? pathLength - 1 : 0);
|
||||
}
|
||||
|
||||
public bool IsRoot(FolderMetadata dropboxFolder)
|
||||
{
|
||||
return dropboxFolder != null && dropboxFolder.Id == "/";
|
||||
}
|
||||
|
||||
|
||||
public Task<long> GetMaxUploadSizeAsync()
|
||||
{
|
||||
return Task.FromResult(MaxChunkedUploadFileSize);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_dropboxClient != null)
|
||||
|
@ -28,375 +28,13 @@ using DriveFile = Google.Apis.Drive.v3.Data.File;
|
||||
|
||||
namespace ASC.Files.Thirdparty.GoogleDrive;
|
||||
|
||||
[Singletone]
|
||||
public class GoogleDriveProviderInfoHelper
|
||||
{
|
||||
private readonly ICache _cacheChildFiles;
|
||||
private readonly ICache _cacheChildFolders;
|
||||
private readonly ICache _cacheEntry;
|
||||
private readonly TimeSpan _cacheExpiration;
|
||||
private readonly ICacheNotify<GoogleDriveCacheItem> _cacheNotify;
|
||||
|
||||
public GoogleDriveProviderInfoHelper(ICacheNotify<GoogleDriveCacheItem> cacheNotify, ICache cache)
|
||||
{
|
||||
_cacheExpiration = TimeSpan.FromMinutes(1);
|
||||
_cacheEntry = cache;
|
||||
_cacheChildFiles = cache;
|
||||
_cacheChildFolders = cache;
|
||||
|
||||
_cacheNotify = cacheNotify;
|
||||
_cacheNotify.Subscribe((i) =>
|
||||
{
|
||||
if (i.ResetEntry)
|
||||
{
|
||||
_cacheEntry.Remove($"{Selectors.GoogleDrive.Id}-" + i.Key);
|
||||
}
|
||||
if (i.ResetAll)
|
||||
{
|
||||
_cacheEntry.Remove(new Regex($"^{Selectors.GoogleDrive.Id}-" + i.Key + ".*"));
|
||||
_cacheChildFiles.Remove(new Regex($"^{Selectors.GoogleDrive.Id}f-" + i.Key + ".*"));
|
||||
_cacheChildFolders.Remove(new Regex($"^{Selectors.GoogleDrive.Id}d-" + i.Key + ".*"));
|
||||
}
|
||||
if (i.ResetChilds)
|
||||
{
|
||||
if (!i.ChildFolderExist || !i.ChildFolder)
|
||||
{
|
||||
_cacheChildFiles.Remove($"{Selectors.GoogleDrive.Id}f-" + i.Key);
|
||||
}
|
||||
if (!i.ChildFolderExist || i.ChildFolder)
|
||||
{
|
||||
_cacheChildFolders.Remove($"{Selectors.GoogleDrive.Id}d-" + i.Key);
|
||||
}
|
||||
}
|
||||
}, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(DriveFile driveEntry, int id)
|
||||
{
|
||||
if (driveEntry != null)
|
||||
{
|
||||
await _cacheNotify.PublishAsync(new GoogleDriveCacheItem { ResetEntry = true, Key = id + "-" + driveEntry.Id }, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(string driveRootId, int id, string driveId = null, bool? childFolder = null)
|
||||
{
|
||||
var key = id + "-";
|
||||
if (driveId == null)
|
||||
{
|
||||
await _cacheNotify.PublishAsync(new GoogleDriveCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (driveId == driveRootId)
|
||||
{
|
||||
driveId = "root";
|
||||
}
|
||||
|
||||
key += driveId;
|
||||
|
||||
await _cacheNotify.PublishAsync(new GoogleDriveCacheItem { ResetEntry = true, ResetChilds = true, Key = key, ChildFolder = childFolder ?? false, ChildFolderExist = childFolder.HasValue }, CacheNotifyAction.Remove);
|
||||
}
|
||||
}
|
||||
|
||||
internal Task CacheResetChildsAsync(int id, string parentDriveId, bool? childFolder = null)
|
||||
{
|
||||
return _cacheNotify.PublishAsync(new GoogleDriveCacheItem { ResetChilds = true, Key = id + "-" + parentDriveId, ChildFolder = childFolder ?? false, ChildFolderExist = childFolder.HasValue }, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
internal async Task<List<DriveFile>> GetDriveEntriesAsync(GoogleDriveStorage storage, int id, string parentDriveId, bool? folder = null)
|
||||
{
|
||||
if (folder.HasValue)
|
||||
{
|
||||
if (folder.Value)
|
||||
{
|
||||
var value = _cacheChildFolders.Get<List<DriveFile>>($"{Selectors.GoogleDrive.Id}d-" + id + "-" + parentDriveId);
|
||||
if (value == null)
|
||||
{
|
||||
value = await storage.GetEntriesAsync(parentDriveId, true);
|
||||
if (value != null)
|
||||
{
|
||||
_cacheChildFolders.Insert($"{Selectors.GoogleDrive.Id}d-" + id + "-" + parentDriveId, value, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = _cacheChildFiles.Get<List<DriveFile>>($"{Selectors.GoogleDrive.Id}f-" + id + "-" + parentDriveId);
|
||||
if (value == null)
|
||||
{
|
||||
value = await storage.GetEntriesAsync(parentDriveId, false);
|
||||
if (value != null)
|
||||
{
|
||||
_cacheChildFiles.Insert($"{Selectors.GoogleDrive.Id}f-" + id + "-" + parentDriveId, value, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (_cacheChildFiles.Get<List<DriveFile>>($"{Selectors.GoogleDrive.Id}f-" + id + "-" + parentDriveId) == null &&
|
||||
_cacheChildFolders.Get<List<DriveFile>>($"{Selectors.GoogleDrive.Id}d-" + id + "-" + parentDriveId) == null)
|
||||
{
|
||||
var entries = await storage.GetEntriesAsync(parentDriveId);
|
||||
|
||||
_cacheChildFiles.Insert($"{Selectors.GoogleDrive.Id}f-" + id + "-" + parentDriveId, entries.Where(entry => entry.MimeType != GoogleLoginProvider.GoogleDriveMimeTypeFolder).ToList(), DateTime.UtcNow.Add(_cacheExpiration));
|
||||
_cacheChildFolders.Insert($"{Selectors.GoogleDrive.Id}d-" + id + "-" + parentDriveId, entries.Where(entry => entry.MimeType == GoogleLoginProvider.GoogleDriveMimeTypeFolder).ToList(), DateTime.UtcNow.Add(_cacheExpiration));
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
var folders = _cacheChildFolders.Get<List<DriveFile>>($"{Selectors.GoogleDrive.Id}d-" + id + "-" + parentDriveId);
|
||||
if (folders == null)
|
||||
{
|
||||
folders = await storage.GetEntriesAsync(parentDriveId, true);
|
||||
_cacheChildFolders.Insert($"{Selectors.GoogleDrive.Id}d-" + id + "-" + parentDriveId, folders, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
|
||||
var files = _cacheChildFiles.Get<List<DriveFile>>($"{Selectors.GoogleDrive.Id}f-" + id + "-" + parentDriveId);
|
||||
if (files == null)
|
||||
{
|
||||
files = await storage.GetEntriesAsync(parentDriveId, false);
|
||||
_cacheChildFiles.Insert($"{Selectors.GoogleDrive.Id}f-" + id + "-" + parentDriveId, files, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
|
||||
return folders.Concat(files).ToList();
|
||||
}
|
||||
|
||||
internal async Task<DriveFile> GetDriveEntryAsync(GoogleDriveStorage storage, int id, string driveId)
|
||||
{
|
||||
var entry = _cacheEntry.Get<DriveFile>($"{Selectors.GoogleDrive.Id}-" + id + "-" + driveId);
|
||||
if (entry == null)
|
||||
{
|
||||
entry = await storage.GetEntryAsync(driveId);
|
||||
if (entry != null)
|
||||
{
|
||||
_cacheEntry.Insert($"{Selectors.GoogleDrive.Id}-" + id + "-" + driveId, entry, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
[Transient]
|
||||
[DebuggerDisplay("{CustomerTitle}")]
|
||||
internal class GoogleDriveProviderInfo : IProviderInfo
|
||||
internal class GoogleDriveProviderInfo : AbstractProviderInfo<DriveFile, DriveFile, DriveFile, GoogleLoginProvider>
|
||||
{
|
||||
private readonly GoogleDriveProviderInfoHelper _googleDriveProviderInfoHelper;
|
||||
private readonly ILogger _logger;
|
||||
private readonly GoogleDriveStorageDisposableWrapper _wrapper;
|
||||
private string _driveRootId;
|
||||
public GoogleDriveProviderInfo(
|
||||
GoogleDriveStorageDisposableWrapper storageDisposableWrapper,
|
||||
GoogleDriveProviderInfoHelper googleDriveProviderInfoHelper,
|
||||
ILoggerProvider options)
|
||||
internal override string Selector { get; } = Selectors.GoogleDrive.Id;
|
||||
|
||||
public GoogleDriveProviderInfo(DisposableWrapper wrapper) : base(wrapper)
|
||||
{
|
||||
_wrapper = storageDisposableWrapper;
|
||||
_googleDriveProviderInfoHelper = googleDriveProviderInfoHelper;
|
||||
_logger = options.CreateLogger("ASC.Files");
|
||||
}
|
||||
|
||||
public DateTime CreateOn { get; set; }
|
||||
public string CustomerTitle { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
public FolderType FolderType { get; set; }
|
||||
public bool HasLogo { get; set; }
|
||||
public int ID { get; set; }
|
||||
public Guid Owner { get; set; }
|
||||
public bool Private { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
public string RootFolderId => $"{Selectors.GoogleDrive.Id}-" + ID;
|
||||
public FolderType RootFolderType { get; set; }
|
||||
public OAuth20Token Token { get; set; }
|
||||
internal bool StorageOpened => _wrapper.TryGetStorage(ID, out var storage) && storage.IsOpened;
|
||||
public string DriveRootId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_driveRootId))
|
||||
{
|
||||
try
|
||||
{
|
||||
_driveRootId = StorageAsync.Result.GetRootFolderId();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorGoogleDrive(ex);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return _driveRootId;
|
||||
}
|
||||
}
|
||||
|
||||
internal Task<GoogleDriveStorage> StorageAsync
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_wrapper.TryGetStorage(ID, out var storage) || !storage.IsOpened)
|
||||
{
|
||||
return _wrapper.CreateStorageAsync(Token, ID);
|
||||
}
|
||||
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> CheckAccessAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Task.FromResult(!string.IsNullOrEmpty(DriveRootId));
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (StorageOpened)
|
||||
{
|
||||
StorageAsync.Result.Close();
|
||||
}
|
||||
}
|
||||
public Task InvalidateStorageAsync()
|
||||
{
|
||||
if (_wrapper != null)
|
||||
{
|
||||
_wrapper.Dispose();
|
||||
}
|
||||
|
||||
return CacheResetAsync();
|
||||
}
|
||||
|
||||
public void UpdateTitle(string newtitle)
|
||||
{
|
||||
CustomerTitle = newtitle;
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(DriveFile driveEntry)
|
||||
{
|
||||
return _googleDriveProviderInfoHelper.CacheResetAsync(driveEntry, ID);
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(string driveId = null, bool? childFolder = null)
|
||||
{
|
||||
return _googleDriveProviderInfoHelper.CacheResetAsync(DriveRootId, ID, driveId, childFolder);
|
||||
}
|
||||
|
||||
internal Task CacheResetChildsAsync(string parentDriveId, bool? childFolder = null)
|
||||
{
|
||||
return _googleDriveProviderInfoHelper.CacheResetChildsAsync(ID, parentDriveId, childFolder);
|
||||
}
|
||||
|
||||
internal async Task<List<DriveFile>> GetDriveEntriesAsync(string parentDriveId, bool? folder = null)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _googleDriveProviderInfoHelper.GetDriveEntriesAsync(storage, ID, parentDriveId, folder);
|
||||
}
|
||||
|
||||
internal async Task<DriveFile> GetDriveEntryAsync(string driveId)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _googleDriveProviderInfoHelper.GetDriveEntryAsync(storage, ID, driveId);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnail(string fileId, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await storage.GetThumbnail(fileId, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Transient(Additional = typeof(GoogleDriveProviderInfoExtention))]
|
||||
internal class GoogleDriveStorageDisposableWrapper : IDisposable
|
||||
{
|
||||
private readonly ConsumerFactory _consumerFactory;
|
||||
private readonly OAuth20TokenHelper _oAuth20TokenHelper;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ConcurrentDictionary<int, GoogleDriveStorage> _storages =
|
||||
new ConcurrentDictionary<int, GoogleDriveStorage>();
|
||||
|
||||
public GoogleDriveStorageDisposableWrapper(ConsumerFactory consumerFactory, IServiceProvider serviceProvider, OAuth20TokenHelper oAuth20TokenHelper)
|
||||
{
|
||||
_consumerFactory = consumerFactory;
|
||||
_serviceProvider = serviceProvider;
|
||||
_oAuth20TokenHelper = oAuth20TokenHelper;
|
||||
}
|
||||
|
||||
public Task<GoogleDriveStorage> CreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (TryGetStorage(id, out var storage) && storage.IsOpened)
|
||||
{
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
|
||||
return InternalCreateStorageAsync(token, id);
|
||||
}
|
||||
|
||||
public bool TryGetStorage(int id, out GoogleDriveStorage storage)
|
||||
{
|
||||
return _storages.TryGetValue(id, out storage);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var (key, storage) in _storages)
|
||||
{
|
||||
storage.Close();
|
||||
_storages.Remove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<GoogleDriveStorage> InternalCreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
var driveStorage = _serviceProvider.GetRequiredService<GoogleDriveStorage>();
|
||||
|
||||
await CheckTokenAsync(token, id);
|
||||
|
||||
driveStorage.Open(token);
|
||||
|
||||
_storages.TryAdd(id, driveStorage);
|
||||
|
||||
return driveStorage;
|
||||
}
|
||||
|
||||
private Task CheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token");
|
||||
}
|
||||
|
||||
return InternalCheckTokenAsync(token, id);
|
||||
}
|
||||
|
||||
private async Task InternalCheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token.IsExpired)
|
||||
{
|
||||
token = _oAuth20TokenHelper.RefreshToken<GoogleLoginProvider>(_consumerFactory, token);
|
||||
|
||||
var dbDao = _serviceProvider.GetService<ProviderAccountDao>();
|
||||
var authData = new AuthData(token: token.ToJson());
|
||||
await dbDao.UpdateProviderInfoAsync(id, authData);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static class GoogleDriveProviderInfoExtention
|
||||
{
|
||||
public static void Register(DIHelper dIHelper)
|
||||
{
|
||||
dIHelper.TryAdd<GoogleDriveStorage>();
|
||||
}
|
||||
}
|
@ -24,13 +24,15 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using System.IO;
|
||||
|
||||
using DriveFile = Google.Apis.Drive.v3.Data.File;
|
||||
using MimeMapping = ASC.Common.Web.MimeMapping;
|
||||
|
||||
namespace ASC.Files.Thirdparty.GoogleDrive;
|
||||
|
||||
[Transient]
|
||||
internal class GoogleDriveStorage : IDisposable
|
||||
internal class GoogleDriveStorage : IThirdPartyStorage<DriveFile, DriveFile, DriveFile>, IDisposable
|
||||
{
|
||||
private OAuth20Token _token;
|
||||
|
||||
@ -130,31 +132,11 @@ internal class GoogleDriveStorage : IDisposable
|
||||
return rootFolder.Id;
|
||||
}
|
||||
|
||||
public DriveFile GetEntry(string entryId)
|
||||
public async Task<DriveFile> GetItemAsync(string itemId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = _driveService.Files.Get(entryId);
|
||||
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return request.Execute();
|
||||
}
|
||||
catch (GoogleApiException ex)
|
||||
{
|
||||
if (ex.HttpStatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DriveFile> GetEntryAsync(string entryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = _driveService.Files.Get(entryId);
|
||||
var request = _driveService.Files.Get(itemId);
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return await request.ExecuteAsync();
|
||||
@ -169,7 +151,7 @@ internal class GoogleDriveStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnail(string fileId, int width, int height)
|
||||
public async Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -184,42 +166,12 @@ internal class GoogleDriveStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public List<DriveFile> GetEntries(string folderId, bool? folders = null)
|
||||
public Task<List<DriveFile>> GetItemsAsync(string folderId)
|
||||
{
|
||||
var request = _driveService.Files.List();
|
||||
|
||||
var query = "'" + folderId + "' in parents and trashed=false";
|
||||
|
||||
if (folders.HasValue)
|
||||
{
|
||||
query += " and mimeType " + (folders.Value ? "" : "!") + "= '" + GoogleLoginProvider.GoogleDriveMimeTypeFolder + "'";
|
||||
}
|
||||
|
||||
request.Q = query;
|
||||
|
||||
request.Fields = "nextPageToken, files(" + GoogleLoginProvider.FilesFields + ")";
|
||||
|
||||
var files = new List<DriveFile>();
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileList = request.Execute();
|
||||
|
||||
files.AddRange(fileList.Files);
|
||||
|
||||
request.PageToken = fileList.NextPageToken;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
request.PageToken = null;
|
||||
}
|
||||
} while (!string.IsNullOrEmpty(request.PageToken));
|
||||
|
||||
return files;
|
||||
return GetItemsInternalAsync(folderId);
|
||||
}
|
||||
|
||||
public async Task<List<DriveFile>> GetEntriesAsync(string folderId, bool? folders = null)
|
||||
private async Task<List<DriveFile>> GetItemsInternalAsync(string folderId, bool? folders = null)
|
||||
{
|
||||
var request = _driveService.Files.List();
|
||||
|
||||
@ -303,37 +255,6 @@ internal class GoogleDriveStorage : IDisposable
|
||||
return tempBuffer;
|
||||
}
|
||||
|
||||
public DriveFile InsertEntry(Stream fileStream, string title, string parentId, bool folder = false)
|
||||
{
|
||||
var mimeType = folder ? GoogleLoginProvider.GoogleDriveMimeTypeFolder : MimeMapping.GetMimeMapping(title);
|
||||
|
||||
var body = FileConstructor(title, mimeType, parentId);
|
||||
|
||||
if (folder)
|
||||
{
|
||||
var requestFolder = _driveService.Files.Create(body);
|
||||
requestFolder.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return requestFolder.Execute();
|
||||
}
|
||||
|
||||
var request = _driveService.Files.Create(body, fileStream, mimeType);
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
var result = request.Upload();
|
||||
if (result.Exception != null)
|
||||
{
|
||||
if (request.ResponseBody == null)
|
||||
{
|
||||
throw result.Exception;
|
||||
}
|
||||
|
||||
_logger.ErrorWhileTryingToInsertEntity(result.Exception);
|
||||
}
|
||||
|
||||
return request.ResponseBody;
|
||||
}
|
||||
|
||||
public async Task<DriveFile> InsertEntryAsync(Stream fileStream, string title, string parentId, bool folder = false)
|
||||
{
|
||||
var mimeType = folder ? GoogleLoginProvider.GoogleDriveMimeTypeFolder : MimeMapping.GetMimeMapping(title);
|
||||
@ -364,15 +285,9 @@ internal class GoogleDriveStorage : IDisposable
|
||||
|
||||
return request.ResponseBody;
|
||||
}
|
||||
|
||||
public void DeleteEntry(string entryId)
|
||||
public Task DeleteItemAsync(DriveFile entry)
|
||||
{
|
||||
_driveService.Files.Delete(entryId).Execute();
|
||||
}
|
||||
|
||||
public Task DeleteEntryAsync(string entryId)
|
||||
{
|
||||
return _driveService.Files.Delete(entryId).ExecuteAsync();
|
||||
return _driveService.Files.Delete(entry.Id).ExecuteAsync();
|
||||
}
|
||||
|
||||
public DriveFile InsertEntryIntoFolder(DriveFile entry, string folderId)
|
||||
@ -393,15 +308,6 @@ internal class GoogleDriveStorage : IDisposable
|
||||
return request.ExecuteAsync();
|
||||
}
|
||||
|
||||
public DriveFile RemoveEntryFromFolder(DriveFile entry, string folderId)
|
||||
{
|
||||
var request = _driveService.Files.Update(FileConstructor(), entry.Id);
|
||||
request.RemoveParents = folderId;
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return request.Execute();
|
||||
}
|
||||
|
||||
public Task<DriveFile> RemoveEntryFromFolderAsync(DriveFile entry, string folderId)
|
||||
{
|
||||
var request = _driveService.Files.Update(FileConstructor(), entry.Id);
|
||||
@ -411,29 +317,9 @@ internal class GoogleDriveStorage : IDisposable
|
||||
return request.ExecuteAsync();
|
||||
}
|
||||
|
||||
public DriveFile CopyEntry(string toFolderId, string originEntryId)
|
||||
public async Task<DriveFile> CopyEntryAsync(string toFolderId, string originEntryId, string newTitle)
|
||||
{
|
||||
var body = FileConstructor(folderId: toFolderId);
|
||||
try
|
||||
{
|
||||
var request = _driveService.Files.Copy(body, originEntryId);
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return request.Execute();
|
||||
}
|
||||
catch (GoogleApiException ex)
|
||||
{
|
||||
if (ex.HttpStatusCode == HttpStatusCode.Forbidden)
|
||||
{
|
||||
throw new SecurityException(ex.Error.Message);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DriveFile> CopyEntryAsync(string toFolderId, string originEntryId)
|
||||
{
|
||||
var body = FileConstructor(folderId: toFolderId);
|
||||
var body = FileConstructor(folderId: toFolderId, title: newTitle);
|
||||
try
|
||||
{
|
||||
var request = _driveService.Files.Copy(body, originEntryId);
|
||||
@ -451,14 +337,6 @@ internal class GoogleDriveStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public DriveFile RenameEntry(string fileId, string newTitle)
|
||||
{
|
||||
var request = _driveService.Files.Update(FileConstructor(newTitle), fileId);
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return request.Execute();
|
||||
}
|
||||
|
||||
public Task<DriveFile> RenameEntryAsync(string fileId, string newTitle)
|
||||
{
|
||||
var request = _driveService.Files.Update(FileConstructor(newTitle), fileId);
|
||||
@ -467,27 +345,6 @@ internal class GoogleDriveStorage : IDisposable
|
||||
return request.ExecuteAsync();
|
||||
}
|
||||
|
||||
public DriveFile SaveStream(string fileId, Stream fileStream, string fileTitle)
|
||||
{
|
||||
var mimeType = MimeMapping.GetMimeMapping(fileTitle);
|
||||
var file = FileConstructor(fileTitle, mimeType);
|
||||
|
||||
var request = _driveService.Files.Update(file, fileId, fileStream, mimeType);
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
var result = request.Upload();
|
||||
if (result.Exception != null)
|
||||
{
|
||||
if (request.ResponseBody == null)
|
||||
{
|
||||
throw result.Exception;
|
||||
}
|
||||
|
||||
_logger.ErrorWhileTryingToInsertEntity(result.Exception);
|
||||
}
|
||||
|
||||
return request.ResponseBody;
|
||||
}
|
||||
|
||||
public async Task<DriveFile> SaveStreamAsync(string fileId, Stream fileStream, string fileTitle)
|
||||
{
|
||||
var mimeType = MimeMapping.GetMimeMapping(fileTitle);
|
||||
@ -701,6 +558,83 @@ internal class GoogleDriveStorage : IDisposable
|
||||
_driveService.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<DriveFile> GetFolderAsync(string folderId)
|
||||
{
|
||||
return GetItemAsync(folderId);
|
||||
}
|
||||
|
||||
public Task<DriveFile> GetFileAsync(string fileId)
|
||||
{
|
||||
return GetItemAsync(fileId);
|
||||
}
|
||||
|
||||
public Task<DriveFile> CreateFolderAsync(string title, string parentId)
|
||||
{
|
||||
return InsertEntryAsync(null, title, parentId, true);
|
||||
}
|
||||
|
||||
public Task<DriveFile> CreateFileAsync(Stream fileStream, string title, string parentId)
|
||||
{
|
||||
return InsertEntryAsync(fileStream, title, parentId);
|
||||
}
|
||||
|
||||
public Task<DriveFile> MoveFolderAsync(string folderId, string newFolderName, string toFolderId)
|
||||
{
|
||||
var body = FileConstructor(newFolderName, toFolderId);
|
||||
var request = _driveService.Files.Update(body, folderId);
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return request.ExecuteAsync();
|
||||
}
|
||||
|
||||
public Task<DriveFile> MoveFileAsync(string fileId, string newFileName, string toFolderId)
|
||||
{
|
||||
var body = FileConstructor(newFileName, toFolderId);
|
||||
var request = _driveService.Files.Update(body, fileId);
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return request.ExecuteAsync();
|
||||
}
|
||||
|
||||
public Task<DriveFile> CopyFolderAsync(string folderId, string newFolderName, string toFolderId)
|
||||
{
|
||||
return CopyEntryAsync(toFolderId, folderId, newFolderName);
|
||||
}
|
||||
|
||||
public Task<DriveFile> CopyFileAsync(string fileId, string newFileName, string toFolderId)
|
||||
{
|
||||
return CopyEntryAsync(toFolderId, fileId, newFileName);
|
||||
}
|
||||
|
||||
public Task<DriveFile> RenameFolderAsync(string folderId, string newName)
|
||||
{
|
||||
return RenameEntryAsync(folderId, newName);
|
||||
}
|
||||
|
||||
public Task<DriveFile> RenameFileAsync(string fileId, string newName)
|
||||
{
|
||||
return RenameEntryAsync(fileId, newName);
|
||||
}
|
||||
|
||||
public async Task<DriveFile> SaveStreamAsync(string fileId, Stream fileStream)
|
||||
{
|
||||
var file = await GetFileAsync(fileId);
|
||||
return await SaveStreamAsync(fileId, fileStream, file.Name);
|
||||
}
|
||||
|
||||
public async Task<bool> CheckAccessAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var rootFolder = await GetFolderAsync("root");
|
||||
return !string.IsNullOrEmpty(rootFolder.Id);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ResumableUploadSessionStatus
|
||||
|
44
products/ASC.Files/Core/Core/Thirdparty/IDaoBase.cs
vendored
Normal file
44
products/ASC.Files/Core/Core/Thirdparty/IDaoBase.cs
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.Files.Core.Core.Thirdparty;
|
||||
internal interface IDaoBase<TFile, TFolder, TItem>
|
||||
{
|
||||
string MakeId(object entryId);
|
||||
string GetParentFolderId(TItem item);
|
||||
string MakeId(TItem item);
|
||||
string MakeId(string path = null);
|
||||
string MakeFolderTitle(TFolder folder);
|
||||
string MakeFileTitle(TFile file);
|
||||
Folder<string> ToFolder(TFolder folder);
|
||||
File<string> ToFile(TFile file);
|
||||
Task<Folder<string>> GetRootFolderAsync();
|
||||
Task<TFolder> GetFolderAsync(string folderId);
|
||||
Task<TFile> GetFileAsync(string fileId);
|
||||
Task<IEnumerable<string>> GetChildrenAsync(string folderId);
|
||||
Task<List<TItem>> GetItemsAsync(string parentId, bool? folder = null);
|
||||
Task<string> GetAvailableTitleAsync(string requestTitle, string parentFolderId, Func<string, string, Task<bool>> isExist);
|
||||
}
|
68
products/ASC.Files/Core/Core/Thirdparty/IThirdPartyStorage.cs
vendored
Normal file
68
products/ASC.Files/Core/Core/Thirdparty/IThirdPartyStorage.cs
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// (c) Copyright Ascensio System SIA 2010-2022
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.Files.Core.Core.Thirdparty;
|
||||
public interface IThirdPartyStorage
|
||||
{
|
||||
bool IsOpened { get; }
|
||||
|
||||
public void Open(OAuth20Token token);
|
||||
public void Close();
|
||||
public Task<long> GetMaxUploadSizeAsync();
|
||||
public Task<bool> CheckAccessAsync();
|
||||
public Task<Stream> GetThumbnailAsync(string fileId, int width, int height);
|
||||
}
|
||||
|
||||
public interface IThirdPartyItemStorage<TItem> : IThirdPartyStorage
|
||||
{
|
||||
public Task<List<TItem>> GetItemsAsync(string folderId);
|
||||
public Task DeleteItemAsync(TItem item);
|
||||
}
|
||||
|
||||
public interface IThirdPartyFileStorage<TFile> : IThirdPartyStorage
|
||||
{
|
||||
public Task<TFile> GetFileAsync(string fileId);
|
||||
public Task<TFile> CreateFileAsync(Stream fileStream, string title, string parentId);
|
||||
public Task<Stream> DownloadStreamAsync(TFile file, int offset = 0);
|
||||
public Task<TFile> MoveFileAsync(string fileId, string newFileName, string toFolderId);
|
||||
public Task<TFile> CopyFileAsync(string fileId, string newFileName, string toFolderId);
|
||||
public Task<TFile> RenameFileAsync(string fileId, string newName);
|
||||
public Task<TFile> SaveStreamAsync(string fileId, Stream fileStream);
|
||||
}
|
||||
|
||||
public interface IThirdPartyFolderStorage<TFolder> : IThirdPartyStorage
|
||||
{
|
||||
public Task<TFolder> GetFolderAsync(string folderId);
|
||||
public Task<TFolder> CreateFolderAsync(string title, string parentId);
|
||||
public Task<TFolder> MoveFolderAsync(string folderId, string newFolderName, string toFolderId);
|
||||
public Task<TFolder> CopyFolderAsync(string folderId, string newFolderName, string toFolderId);
|
||||
public Task<TFolder> RenameFolderAsync(string folderId, string newName);
|
||||
}
|
||||
|
||||
public interface IThirdPartyStorage<TFile, TFolder, TItem> : IThirdPartyFileStorage<TFile>, IThirdPartyFolderStorage<TFolder>, IThirdPartyItemStorage<TItem>
|
||||
{
|
||||
|
||||
}
|
@ -26,289 +26,13 @@
|
||||
|
||||
namespace ASC.Files.Thirdparty.OneDrive;
|
||||
|
||||
[Singletone]
|
||||
public class OneDriveProviderInfoHelper
|
||||
{
|
||||
private readonly ICache _cacheChildItems;
|
||||
private readonly TimeSpan _cacheExpiration;
|
||||
private readonly ICache _cacheItem;
|
||||
private readonly ICacheNotify<OneDriveCacheItem> _cacheNotify;
|
||||
|
||||
public OneDriveProviderInfoHelper(ICacheNotify<OneDriveCacheItem> cacheNotify, ICache cache)
|
||||
{
|
||||
_cacheExpiration = TimeSpan.FromMinutes(1);
|
||||
_cacheItem = cache;
|
||||
_cacheChildItems = cache;
|
||||
|
||||
_cacheNotify = cacheNotify;
|
||||
_cacheNotify.Subscribe((i) =>
|
||||
{
|
||||
ResetMemoryCache(i);
|
||||
if (i.ResetAll)
|
||||
{
|
||||
_cacheChildItems.Remove(new Regex($"^{Selectors.OneDrive.Id}i-" + i.Key + ".*"));
|
||||
_cacheItem.Remove(new Regex($"^{Selectors.OneDrive.Id}-" + i.Key + ".*"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_cacheChildItems.Remove(new Regex($"{Selectors.OneDrive.Id}i-" + i.Key));
|
||||
_cacheItem.Remove($"{Selectors.OneDrive.Id}-" + i.Key);
|
||||
}
|
||||
}, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
internal async Task CacheResetAsync(int id, string onedriveId = null)
|
||||
{
|
||||
var key = id + "-";
|
||||
var item = new OneDriveCacheItem { Key = key };
|
||||
|
||||
if (string.IsNullOrEmpty(onedriveId))
|
||||
{
|
||||
item.ResetAll = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Key += onedriveId;
|
||||
}
|
||||
|
||||
ResetMemoryCache(item);
|
||||
await _cacheNotify.PublishAsync(item, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
internal async Task<Item> GetOneDriveItemAsync(OneDriveStorage storage, int id, string itemId)
|
||||
{
|
||||
var file = _cacheItem.Get<Item>($"{Selectors.OneDrive.Id}-" + id + "-" + itemId);
|
||||
if (file == null)
|
||||
{
|
||||
file = await storage.GetItemAsync(itemId);
|
||||
if (file != null)
|
||||
{
|
||||
_cacheItem.Insert($"{Selectors.OneDrive.Id}-" + id + "-" + itemId, file, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
internal async Task<List<Item>> GetOneDriveItemsAsync(OneDriveStorage storage, int id, string onedriveFolderId)
|
||||
{
|
||||
var items = _cacheChildItems.Get<List<Item>>($"{Selectors.OneDrive.Id}i-" + id + "-" + onedriveFolderId);
|
||||
|
||||
if (items == null)
|
||||
{
|
||||
items = await storage.GetItemsAsync(onedriveFolderId);
|
||||
_cacheChildItems.Insert($"{Selectors.OneDrive.Id}i-" + id + "-" + onedriveFolderId, items, DateTime.UtcNow.Add(_cacheExpiration));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
internal async Task<Stream> GetThumbnailAsync(OneDriveStorage storage, string onedriveId, int width, int height)
|
||||
{
|
||||
return await storage.GetThumbnailAsync(onedriveId, width, height);
|
||||
}
|
||||
|
||||
private void ResetMemoryCache(OneDriveCacheItem i)
|
||||
{
|
||||
if (i.ResetAll)
|
||||
{
|
||||
_cacheChildItems.Remove(new Regex("^onedrivei-" + i.Key + ".*"));
|
||||
_cacheItem.Remove(new Regex("^onedrive-" + i.Key + ".*"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_cacheChildItems.Remove(new Regex($"{Selectors.OneDrive.Id}i-" + i.Key));
|
||||
_cacheItem.Remove($"{Selectors.OneDrive.Id}-" + i.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Transient]
|
||||
[DebuggerDisplay("{CustomerTitle}")]
|
||||
internal class OneDriveProviderInfo : IProviderInfo
|
||||
internal class OneDriveProviderInfo : AbstractProviderInfo<Item, Item, Item, OneDriveLoginProvider>
|
||||
{
|
||||
private readonly OneDriveProviderInfoHelper _oneDriveProviderInfoHelper;
|
||||
private readonly OneDriveStorageDisposableWrapper _wrapper;
|
||||
internal override string Selector { get; } = Selectors.OneDrive.Id;
|
||||
|
||||
public OneDriveProviderInfo(
|
||||
OneDriveStorageDisposableWrapper wrapper,
|
||||
OneDriveProviderInfoHelper oneDriveProviderInfoHelper)
|
||||
public OneDriveProviderInfo(DisposableWrapper wrapper) : base(wrapper)
|
||||
{
|
||||
_wrapper = wrapper;
|
||||
_oneDriveProviderInfoHelper = oneDriveProviderInfoHelper;
|
||||
}
|
||||
|
||||
public DateTime CreateOn { get; set; }
|
||||
public string CustomerTitle { get; set; }
|
||||
public string FolderId { get; set; }
|
||||
public FolderType FolderType { get; set; }
|
||||
public bool HasLogo { get; set; }
|
||||
public int ID { get; set; }
|
||||
public Guid Owner { get; set; }
|
||||
public bool Private { get; set; }
|
||||
public string ProviderKey { get; set; }
|
||||
public string RootFolderId => $"{Selectors.OneDrive.Id}-" + ID;
|
||||
public FolderType RootFolderType { get; set; }
|
||||
public OAuth20Token Token { get; set; }
|
||||
internal bool StorageOpened => _wrapper.TryGetStorage(ID, out var storage) && storage.IsOpened;
|
||||
|
||||
internal Task<OneDriveStorage> StorageAsync
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_wrapper.TryGetStorage(ID, out var storage) || !storage.IsOpened)
|
||||
{
|
||||
return _wrapper.CreateStorageAsync(Token, ID);
|
||||
}
|
||||
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> CheckAccessAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await storage.CheckAccessAsync();
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (StorageOpened)
|
||||
{
|
||||
StorageAsync.Result.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public Task InvalidateStorageAsync()
|
||||
{
|
||||
if (_wrapper != null)
|
||||
{
|
||||
_wrapper.Dispose();
|
||||
}
|
||||
|
||||
return CacheResetAsync();
|
||||
}
|
||||
|
||||
public void UpdateTitle(string newtitle)
|
||||
{
|
||||
CustomerTitle = newtitle;
|
||||
}
|
||||
|
||||
internal Task CacheResetAsync(string onedriveId = null)
|
||||
{
|
||||
return _oneDriveProviderInfoHelper.CacheResetAsync(ID, onedriveId);
|
||||
}
|
||||
|
||||
internal async Task<Item> GetOneDriveItemAsync(string itemId)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _oneDriveProviderInfoHelper.GetOneDriveItemAsync(storage, ID, itemId);
|
||||
}
|
||||
|
||||
internal async Task<List<Item>> GetOneDriveItemsAsync(string onedriveFolderId)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
|
||||
return await _oneDriveProviderInfoHelper.GetOneDriveItemsAsync(storage, ID, onedriveFolderId);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(string onedriveId, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _oneDriveProviderInfoHelper.GetThumbnailAsync(storage, onedriveId, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Transient(Additional = typeof(OneDriveProviderInfoExtention))]
|
||||
internal class OneDriveStorageDisposableWrapper : IDisposable
|
||||
{
|
||||
internal readonly ConsumerFactory ConsumerFactory;
|
||||
internal readonly IServiceProvider ServiceProvider;
|
||||
private readonly OAuth20TokenHelper _oAuth20TokenHelper;
|
||||
private readonly ConcurrentDictionary<int, OneDriveStorage> _storages =
|
||||
new ConcurrentDictionary<int, OneDriveStorage>();
|
||||
|
||||
public OneDriveStorageDisposableWrapper(ConsumerFactory consumerFactory, IServiceProvider serviceProvider, OAuth20TokenHelper oAuth20TokenHelper)
|
||||
{
|
||||
ConsumerFactory = consumerFactory;
|
||||
ServiceProvider = serviceProvider;
|
||||
_oAuth20TokenHelper = oAuth20TokenHelper;
|
||||
}
|
||||
|
||||
public Task<OneDriveStorage> CreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (TryGetStorage(id, out var storage) && storage.IsOpened)
|
||||
{
|
||||
return Task.FromResult(storage);
|
||||
}
|
||||
|
||||
return InternalCreateStorageAsync(token, id);
|
||||
}
|
||||
|
||||
public bool TryGetStorage(int id, out OneDriveStorage storage)
|
||||
{
|
||||
return _storages.TryGetValue(id, out storage);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var (key, storage) in _storages)
|
||||
{
|
||||
if (storage.IsOpened)
|
||||
{
|
||||
storage.Close();
|
||||
_storages.Remove(key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Task CheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token");
|
||||
}
|
||||
|
||||
return InternalCheckTokenAsync(token, id);
|
||||
}
|
||||
|
||||
private async Task InternalCheckTokenAsync(OAuth20Token token, int id)
|
||||
{
|
||||
if (token.IsExpired)
|
||||
{
|
||||
token = _oAuth20TokenHelper.RefreshToken<OneDriveLoginProvider>(ConsumerFactory, token);
|
||||
|
||||
var dbDao = ServiceProvider.GetService<ProviderAccountDao>();
|
||||
var authData = new AuthData(token: token.ToJson());
|
||||
await dbDao.UpdateProviderInfoAsync(id, authData);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<OneDriveStorage> InternalCreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
var oneDriveStorage = ServiceProvider.GetRequiredService<OneDriveStorage>();
|
||||
|
||||
await CheckTokenAsync(token, id);
|
||||
|
||||
oneDriveStorage.Open(token);
|
||||
|
||||
_storages.TryAdd(id, oneDriveStorage);
|
||||
|
||||
return oneDriveStorage;
|
||||
}
|
||||
}
|
||||
public static class OneDriveProviderInfoExtention
|
||||
{
|
||||
public static void Register(DIHelper dIHelper)
|
||||
{
|
||||
dIHelper.TryAdd<OneDriveStorage>();
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ using Folder = Microsoft.OneDrive.Sdk.Folder;
|
||||
namespace ASC.Files.Thirdparty.OneDrive;
|
||||
|
||||
[Transient]
|
||||
internal class OneDriveStorage
|
||||
internal class OneDriveStorage : IThirdPartyStorage<Item, Item, Item>
|
||||
{
|
||||
private OAuth20Token _token;
|
||||
|
||||
@ -128,7 +128,7 @@ internal class OneDriveStorage
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<Item>> GetItemsAsync(string folderId, int limit = 500)
|
||||
public async Task<List<Item>> GetItemsAsync(string folderId)
|
||||
{
|
||||
return new List<Item>(await GetItemRequest(folderId).Children.Request().GetAsync());
|
||||
}
|
||||
@ -378,6 +378,51 @@ internal class OneDriveStorage
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<Item> GetFolderAsync(string folderId)
|
||||
{
|
||||
return GetItemAsync(folderId);
|
||||
}
|
||||
|
||||
public Task<Item> GetFileAsync(string fileId)
|
||||
{
|
||||
return GetItemAsync(fileId);
|
||||
}
|
||||
|
||||
public Task<Item> MoveFolderAsync(string folderId, string newFolderName, string toFolderId)
|
||||
{
|
||||
return MoveItemAsync(folderId, newFolderName, toFolderId);
|
||||
}
|
||||
|
||||
public Task<Item> MoveFileAsync(string fileId, string newFileName, string toFolderId)
|
||||
{
|
||||
return MoveItemAsync(fileId, newFileName, toFolderId);
|
||||
}
|
||||
|
||||
public Task<Item> CopyFolderAsync(string folderId, string newFolderName, string toFolderId)
|
||||
{
|
||||
return CopyItemAsync(folderId, newFolderName, toFolderId);
|
||||
}
|
||||
|
||||
public Task<Item> CopyFileAsync(string fileId, string newFileName, string toFolderId)
|
||||
{
|
||||
return CopyItemAsync(fileId, newFileName, toFolderId);
|
||||
}
|
||||
|
||||
public Task<Item> RenameFolderAsync(string folderId, string newName)
|
||||
{
|
||||
return RenameItemAsync(folderId, newName);
|
||||
}
|
||||
|
||||
public Task<Item> RenameFileAsync(string fileId, string newName)
|
||||
{
|
||||
return RenameItemAsync(fileId, newName);
|
||||
}
|
||||
|
||||
public Task<long> GetMaxUploadSizeAsync()
|
||||
{
|
||||
return Task.FromResult(MaxChunkedUploadFileSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@ public static class Selectors
|
||||
public static readonly Selector OneDrive = new Selector() { Name = "OneDrive", Id = "onedrive" };
|
||||
|
||||
public static readonly List<Selector> All = new List<Selector>() { SharpBox, SharePoint, GoogleDrive, Box, Dropbox, OneDrive };
|
||||
public static readonly List<Selector> StoredCache = new List<Selector>() { GoogleDrive, Box, Dropbox, OneDrive };
|
||||
}
|
||||
|
||||
public class Selector
|
||||
|
@ -523,7 +523,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
{
|
||||
fileEntry.CreateBy = ProviderInfo.Owner;
|
||||
fileEntry.ModifiedBy = ProviderInfo.Owner;
|
||||
fileEntry.ProviderId = ProviderInfo.ID;
|
||||
fileEntry.ProviderId = ProviderInfo.ProviderId;
|
||||
fileEntry.ProviderKey = ProviderInfo.ProviderKey;
|
||||
fileEntry.RootCreateBy = ProviderInfo.Owner;
|
||||
fileEntry.RootFolderType = ProviderInfo.RootFolderType;
|
||||
@ -566,7 +566,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
FilterType.MediaOnly;
|
||||
}
|
||||
|
||||
protected abstract string MakeId(string path = null);
|
||||
public abstract string MakeId(string path = null);
|
||||
|
||||
public async IAsyncEnumerable<Tag> GetNewTagsAsync(Guid subject, Folder<string> parentFolder, bool deepSearch)
|
||||
{
|
||||
@ -633,7 +633,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Task<IEnumerable<string>> GetChildrenAsync(string folderId);
|
||||
public abstract Task<IEnumerable<string>> GetChildrenAsync(string folderId);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user