Merge branch 'develop' into feature/integration-system
This commit is contained in:
commit
9d8a3c0104
@ -61,8 +61,8 @@ public class CustomEndpointDataSource : EndpointDataSource
|
||||
void AddEndpoints(IReadOnlyDictionary<string, object> defaults = null, RouteValueDictionary policies = null)
|
||||
{
|
||||
var order = constraintRouteAttr != null ? r.Order : r.Order + 2;
|
||||
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText, defaults, policies), order, r.Metadata, r.DisplayName));
|
||||
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}", defaults, policies), order - 1, r.Metadata, r.DisplayName));
|
||||
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText, defaults, policies), order + 1, r.Metadata, r.DisplayName));
|
||||
endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}", defaults, policies), order, r.Metadata, r.DisplayName));
|
||||
}
|
||||
|
||||
}).ToList();
|
||||
|
@ -31,7 +31,7 @@ public class TempPath
|
||||
{
|
||||
private readonly string _tempFolder;
|
||||
|
||||
public TempPath(IConfiguration configuration)
|
||||
public TempPath(IHostEnvironment hostEnvironment, IConfiguration configuration)
|
||||
{
|
||||
var rootFolder = AppContext.BaseDirectory;
|
||||
if (string.IsNullOrEmpty(rootFolder))
|
||||
@ -39,7 +39,7 @@ public class TempPath
|
||||
rootFolder = Assembly.GetEntryAssembly().Location;
|
||||
}
|
||||
|
||||
_tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
|
||||
_tempFolder = configuration["web:temp"] ?? CrossPlatform.PathCombine(hostEnvironment.ContentRootPath, "temp");
|
||||
if (!Path.IsPathRooted(_tempFolder))
|
||||
{
|
||||
_tempFolder = Path.GetFullPath(Path.Combine(rootFolder, _tempFolder));
|
||||
@ -56,7 +56,7 @@ public class TempPath
|
||||
return _tempFolder;
|
||||
}
|
||||
|
||||
public string GetTempFileName()
|
||||
public string GetTempFileName(string ext = "")
|
||||
{
|
||||
FileStream f = null;
|
||||
string path;
|
||||
@ -66,6 +66,11 @@ public class TempPath
|
||||
{
|
||||
path = Path.Combine(_tempFolder, Path.GetRandomFileName());
|
||||
|
||||
if (!string.IsNullOrEmpty(ext))
|
||||
{
|
||||
path = Path.ChangeExtension(path, ext);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (f = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read))
|
||||
|
@ -54,7 +54,12 @@ public class TempStream
|
||||
|
||||
public Stream Create()
|
||||
{
|
||||
return new FileStream(_tempPath.GetTempFileName(), FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
|
||||
return Create(out _);
|
||||
}
|
||||
|
||||
public Stream Create(out string path, string ext = "")
|
||||
{
|
||||
path = _tempPath.GetTempFileName(ext);
|
||||
return new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
}
|
@ -86,6 +86,7 @@ global using Microsoft.Extensions.Caching.Memory;
|
||||
global using Microsoft.Extensions.Configuration;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
global using Microsoft.Extensions.Hosting;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using Microsoft.Extensions.Options;
|
||||
global using Microsoft.Extensions.Primitives;
|
||||
|
@ -1,53 +1,53 @@
|
||||
// (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;
|
||||
|
||||
[Scope]
|
||||
public interface IFileDao<T>
|
||||
{
|
||||
// (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;
|
||||
|
||||
[Scope]
|
||||
public interface IFileDao<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Clear the application cache for the specific file
|
||||
/// </summary>
|
||||
Task InvalidateCacheAsync(T fileId);
|
||||
/// </summary>
|
||||
Task InvalidateCacheAsync(T fileId);
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileAsync(T fileId);
|
||||
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileAsync(T fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileAsync(T fileId, int fileVersion);
|
||||
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileAsync(T fileId, int fileVersion);
|
||||
|
||||
/// <summary>
|
||||
/// Receive file
|
||||
/// </summary>
|
||||
@ -55,29 +55,29 @@ public interface IFileDao<T>
|
||||
/// <param name="title">file name</param>
|
||||
/// <returns>
|
||||
/// file
|
||||
/// </returns>
|
||||
Task<File<T>> GetFileAsync(T parentId, string title);
|
||||
/// </returns>
|
||||
Task<File<T>> GetFileAsync(T parentId, string title);
|
||||
/// <summary>
|
||||
/// Receive last file without forcesave
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion"></param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> GetFileStableAsync(T fileId, int fileVersion = -1);
|
||||
Task<File<T>> GetFileStableAsync(T fileId, int fileVersion = -1);
|
||||
/// <summary>
|
||||
/// Returns all versions of the file
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFileHistoryAsync(T fileId);
|
||||
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFileHistoryAsync(T fileId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file (s) by ID (s)
|
||||
/// </summary>
|
||||
/// <param name="fileIds">id file</param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> fileIds);
|
||||
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFilesAsync(IEnumerable<T> fileIds);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file (s) by ID (s) for share
|
||||
/// </summary>
|
||||
@ -88,15 +88,15 @@ public interface IFileDao<T>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<File<T>> GetFilesFilteredAsync(IEnumerable<T> fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool checkShared = false);
|
||||
|
||||
IAsyncEnumerable<File<T>> GetFilesFilteredAsync(IEnumerable<T> fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool checkShared = false);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<T>> GetFilesAsync(T parentId);
|
||||
|
||||
/// <returns></returns>
|
||||
Task<List<T>> GetFilesAsync(T parentId);
|
||||
|
||||
/// <summary>
|
||||
/// Get files in folder
|
||||
/// </summary>
|
||||
@ -111,39 +111,39 @@ public interface IFileDao<T>
|
||||
/// <returns>list of files</returns>
|
||||
/// <remarks>
|
||||
/// Return only the latest versions of files of a folder
|
||||
/// </remarks>
|
||||
IAsyncEnumerable<File<T>> GetFilesAsync(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false);
|
||||
|
||||
/// </remarks>
|
||||
IAsyncEnumerable<File<T>> GetFilesAsync(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false);
|
||||
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns>Stream</returns>
|
||||
Task<Stream> GetFileStreamAsync(File<T> file);
|
||||
|
||||
/// <returns>Stream</returns>
|
||||
Task<Stream> GetFileStreamAsync(File<T> file);
|
||||
|
||||
/// <summary>
|
||||
/// Get stream of file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns>Stream</returns>
|
||||
Task<Stream> GetFileStreamAsync(File<T> file, long offset);
|
||||
|
||||
/// <returns>Stream</returns>
|
||||
Task<Stream> GetFileStreamAsync(File<T> file, long offset);
|
||||
|
||||
/// <summary>
|
||||
/// Get presigned uri
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="expires"></param>
|
||||
/// <returns>Stream uri</returns>
|
||||
Task<Uri> GetPreSignedUriAsync(File<T> file, TimeSpan expires);
|
||||
|
||||
/// <returns>Stream uri</returns>
|
||||
Task<Uri> GetPreSignedUriAsync(File<T> file, TimeSpan expires);
|
||||
|
||||
/// <summary>
|
||||
/// Check is supported PreSignedUri
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns>Stream uri</returns>
|
||||
Task<bool> IsSupportedPreSignedUriAsync(File<T> file);
|
||||
|
||||
/// <returns>Stream uri</returns>
|
||||
Task<bool> IsSupportedPreSignedUriAsync(File<T> file);
|
||||
|
||||
/// <summary>
|
||||
/// Saves / updates the version of the file
|
||||
/// and save stream of file
|
||||
@ -158,96 +158,96 @@ public interface IFileDao<T>
|
||||
///
|
||||
/// Save in all other cases
|
||||
/// </remarks>
|
||||
Task<File<T>> SaveFileAsync(File<T> file, Stream fileStream);
|
||||
Task<File<T>> SaveFileAsync(File<T> file, Stream fileStream);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <returns></returns>
|
||||
Task<File<T>> ReplaceFileVersionAsync(File<T> file, Stream fileStream);
|
||||
Task<File<T>> ReplaceFileVersionAsync(File<T> file, Stream fileStream);
|
||||
/// <summary>
|
||||
/// Deletes a file including all previous versions
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
Task DeleteFileAsync(T fileId);
|
||||
Task DeleteFileAsync(T fileId);
|
||||
/// <summary>
|
||||
/// Checks whether or not file
|
||||
/// </summary>
|
||||
/// <param name="title">file name</param>
|
||||
/// <param name="folderId">folder id</param>
|
||||
/// <returns>Returns true if the file exists, otherwise false</returns>
|
||||
Task<bool> IsExistAsync(string title, object folderId);
|
||||
Task<bool> IsExistAsync(string title, object folderId);
|
||||
/// <summary>
|
||||
/// Moves a file or set of files in a folder
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="toFolderId">The ID of the destination folder</param>
|
||||
Task<T> MoveFileAsync(T fileId, T toFolderId);
|
||||
Task<TTo> MoveFileAsync<TTo>(T fileId, TTo toFolderId);
|
||||
Task<string> MoveFileAsync(T fileId, string toFolderId);
|
||||
Task<int> MoveFileAsync(T fileId, int toFolderId);
|
||||
|
||||
/// <param name="toFolderId">The ID of the destination folder</param>
|
||||
Task<T> MoveFileAsync(T fileId, T toFolderId);
|
||||
Task<TTo> MoveFileAsync<TTo>(T fileId, TTo toFolderId);
|
||||
Task<string> MoveFileAsync(T fileId, string toFolderId);
|
||||
Task<int> MoveFileAsync(T fileId, int toFolderId);
|
||||
|
||||
/// <summary>
|
||||
/// Copy the files in a folder
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="toFolderId">The ID of the destination folder</param>
|
||||
Task<File<T>> CopyFileAsync(T fileId, T toFolderId);
|
||||
Task<File<TTo>> CopyFileAsync<TTo>(T fileId, TTo toFolderId);
|
||||
Task<File<string>> CopyFileAsync(T fileId, string toFolderId);
|
||||
Task<File<int>> CopyFileAsync(T fileId, int toFolderId);
|
||||
|
||||
/// <param name="toFolderId">The ID of the destination folder</param>
|
||||
Task<File<T>> CopyFileAsync(T fileId, T toFolderId);
|
||||
Task<File<TTo>> CopyFileAsync<TTo>(T fileId, TTo toFolderId);
|
||||
Task<File<string>> CopyFileAsync(T fileId, string toFolderId);
|
||||
Task<File<int>> CopyFileAsync(T fileId, int toFolderId);
|
||||
|
||||
/// <summary>
|
||||
/// Rename file
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <param name="newTitle">new name</param>
|
||||
Task<T> FileRenameAsync(File<T> file, string newTitle);
|
||||
|
||||
/// <param name="newTitle">new name</param>
|
||||
Task<T> FileRenameAsync(File<T> file, string newTitle);
|
||||
|
||||
/// <summary>
|
||||
/// Update comment file
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
/// <param name="comment">new comment</param>
|
||||
Task<string> UpdateCommentAsync(T fileId, int fileVersion, string comment);
|
||||
Task<string> UpdateCommentAsync(T fileId, int fileVersion, string comment);
|
||||
/// <summary>
|
||||
/// Complete file version
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
Task CompleteVersionAsync(T fileId, int fileVersion);
|
||||
/// <param name="fileVersion">file version</param>
|
||||
Task CompleteVersionAsync(T fileId, int fileVersion);
|
||||
/// <summary>
|
||||
/// Continue file version
|
||||
/// </summary>
|
||||
/// <param name="fileId">file id</param>
|
||||
/// <param name="fileVersion">file version</param>
|
||||
Task ContinueVersionAsync(T fileId, int fileVersion);
|
||||
/// <param name="fileVersion">file version</param>
|
||||
Task ContinueVersionAsync(T fileId, int fileVersion);
|
||||
/// <summary>
|
||||
/// Check the need to use the trash before removing
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
bool UseTrashForRemove(File<T> file);
|
||||
string GetUniqFilePath(File<T> file, string fileTitle);
|
||||
|
||||
bool UseTrashForRemove(File<T> file);
|
||||
string GetUniqFilePath(File<T> file, string fileTitle);
|
||||
|
||||
#region chunking
|
||||
|
||||
Task<ChunkedUploadSession<T>> CreateUploadSessionAsync(File<T> file, long contentLength);
|
||||
Task<File<T>> UploadChunkAsync(ChunkedUploadSession<T> uploadSession, Stream chunkStream, long chunkLength);
|
||||
Task AbortUploadSessionAsync(ChunkedUploadSession<T> uploadSession);
|
||||
|
||||
Task<ChunkedUploadSession<T>> CreateUploadSessionAsync(File<T> file, long contentLength);
|
||||
Task<File<T>> UploadChunkAsync(ChunkedUploadSession<T> uploadSession, Stream chunkStream, long chunkLength);
|
||||
Task AbortUploadSessionAsync(ChunkedUploadSession<T> uploadSession);
|
||||
#endregion
|
||||
|
||||
|
||||
#region Only in TMFileDao
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set created by
|
||||
/// </summary>
|
||||
/// <param name="fileIds"></param>
|
||||
/// <param name="newOwnerId"></param>
|
||||
Task ReassignFilesAsync(T[] fileIds, Guid newOwnerId);
|
||||
|
||||
/// <param name="newOwnerId"></param>
|
||||
Task ReassignFilesAsync(T[] fileIds, Guid newOwnerId);
|
||||
|
||||
/// <summary>
|
||||
/// Search files in SharedWithMe & Projects
|
||||
/// </summary>
|
||||
@ -258,7 +258,7 @@ public interface IFileDao<T>
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<File<T>>> GetFilesAsync(IEnumerable<T> parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);
|
||||
Task<List<File<T>>> GetFilesAsync(IEnumerable<T> parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);
|
||||
/// <summary>
|
||||
/// Search the list of files containing text
|
||||
/// Only in TMFileDao
|
||||
@ -266,34 +266,36 @@ public interface IFileDao<T>
|
||||
/// <param name="text">search text</param>
|
||||
/// <param name="bunch"></param>
|
||||
/// <returns>list of files</returns>
|
||||
IAsyncEnumerable<File<T>> SearchAsync(string text, bool bunch = false);
|
||||
IAsyncEnumerable<File<T>> SearchAsync(string text, bool bunch = false);
|
||||
/// <summary>
|
||||
/// Checks whether file exists on storage
|
||||
/// </summary>
|
||||
/// <param name="file">file</param>
|
||||
/// <returns></returns>
|
||||
|
||||
Task<bool> IsExistOnStorageAsync(File<T> file);
|
||||
|
||||
Task SaveEditHistoryAsync(File<T> file, string changes, Stream differenceStream);
|
||||
|
||||
Task<List<EditHistory>> GetEditHistoryAsync(DocumentServiceHelper documentServiceHelper, T fileId, int fileVersion = 0);
|
||||
|
||||
Task<Stream> GetDifferenceStreamAsync(File<T> file);
|
||||
|
||||
Task<bool> ContainChangesAsync(T fileId, int fileVersion);
|
||||
|
||||
Task SaveThumbnailAsync(File<T> file, Stream thumbnail, int width, int height);
|
||||
|
||||
Task<Stream> GetThumbnailAsync(File<T> file, int width, int height);
|
||||
|
||||
Task<IEnumerable<FileWithShare>> GetFeedsAsync(int tenant, DateTime from, DateTime to);
|
||||
|
||||
Task<IEnumerable<int>> GetTenantsWithFeedsAsync(DateTime fromTime);
|
||||
|
||||
Task<EntryProperties> GetProperties(T fileId);
|
||||
|
||||
Task SaveProperties(T fileId, EntryProperties entryProperties);
|
||||
|
||||
|
||||
Task<bool> IsExistOnStorageAsync(File<T> file);
|
||||
|
||||
Task SaveEditHistoryAsync(File<T> file, string changes, Stream differenceStream);
|
||||
|
||||
Task<List<EditHistory>> GetEditHistoryAsync(DocumentServiceHelper documentServiceHelper, T fileId, int fileVersion = 0);
|
||||
|
||||
Task<Stream> GetDifferenceStreamAsync(File<T> file);
|
||||
|
||||
Task<bool> ContainChangesAsync(T fileId, int fileVersion);
|
||||
|
||||
Task SaveThumbnailAsync(File<T> file, Stream thumbnail, int width, int height);
|
||||
|
||||
Task<Stream> GetThumbnailAsync(File<T> file, int width, int height);
|
||||
|
||||
Task<Stream> GetThumbnailAsync(T fileId, int width, int height);
|
||||
|
||||
Task<IEnumerable<FileWithShare>> GetFeedsAsync(int tenant, DateTime from, DateTime to);
|
||||
|
||||
Task<IEnumerable<int>> GetTenantsWithFeedsAsync(DateTime fromTime);
|
||||
|
||||
Task<EntryProperties> GetProperties(T fileId);
|
||||
|
||||
Task SaveProperties(T fileId, EntryProperties entryProperties);
|
||||
|
||||
#endregion
|
||||
}
|
@ -1465,6 +1465,12 @@ internal class FileDao : AbstractDao, IFileDao<int>
|
||||
await _globalStore.GetStore().SaveAsync(string.Empty, GetUniqFilePath(file, thumnailName), thumbnail, thumnailName);
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnailAsync(int fileId, int width, int height)
|
||||
{
|
||||
var file = await GetFileAsync(fileId);
|
||||
return await GetThumbnailAsync(file, width, height);
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnailAsync(File<int> file, int width, int height)
|
||||
{
|
||||
var thumnailName = GetThumnailName(width, height);
|
||||
|
@ -192,6 +192,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao<BoxProviderInfo>
|
||||
file.ModifiedOn = boxFile.ModifiedAt.HasValue ? _tenantUtil.DateTimeFromUtc(boxFile.ModifiedAt.Value.UtcDateTime) : default;
|
||||
file.NativeAccessor = boxFile;
|
||||
file.Title = MakeFileTitle(boxFile);
|
||||
file.ThumbnailStatus = Thumbnail.Created;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
@ -550,6 +550,12 @@ internal class BoxFileDao : BoxDaoBase, IFileDao<string>
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
var boxFileId = MakeBoxId(_boxDaoSelector.ConvertId(fileId));
|
||||
return ProviderInfo.GetThumbnailAsync(boxFileId, width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
|
@ -147,6 +147,12 @@ internal class BoxProviderInfo : IProviderInfo
|
||||
{
|
||||
return _boxProviderInfoHelper.CacheResetAsync(BoxRootId, ID, boxPath, isFile);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(string boxFileId, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _boxProviderInfoHelper.GetThumbnailAsync(storage, boxFileId, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Scope]
|
||||
@ -332,4 +338,9 @@ public class BoxProviderInfoHelper
|
||||
await _cacheNotify.PublishAsync(new BoxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(BoxStorage storage, string boxFileId, int width, int height)
|
||||
{
|
||||
return await storage.GetThumbnailAsync(boxFileId, width, height).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -270,4 +270,13 @@ internal class BoxStorage
|
||||
//todo: without chunked uploader:
|
||||
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]";
|
||||
return await _boxClient.FilesManager.GetRepresentationContentAsync(boxRepresentation);
|
||||
}
|
||||
}
|
||||
|
@ -196,6 +196,7 @@ internal abstract class DropboxDaoBase : ThirdPartyProviderDao<DropboxProviderIn
|
||||
file.ModifiedOn = _tenantUtil.DateTimeFromUtc(dropboxFile.ServerModified);
|
||||
file.NativeAccessor = dropboxFile;
|
||||
file.Title = MakeFileTitle(dropboxFile);
|
||||
file.ThumbnailStatus = Thumbnail.Created;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
@ -185,6 +185,7 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
|
||||
}
|
||||
|
||||
//Get only files
|
||||
|
||||
var items = await GetDropboxItemsAsync(parentId, false).ConfigureAwait(false);
|
||||
var files = items.Select(item => ToFile(item.AsFile));
|
||||
|
||||
@ -548,6 +549,11 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao<string>
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId), width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
|
@ -132,9 +132,15 @@ internal class DropboxProviderInfo : IProviderInfo
|
||||
{
|
||||
return _dropboxProviderInfoHelper.CacheResetAsync(ID, dropboxPath, isFile);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailsAsync(string filePath, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _dropboxProviderInfoHelper.GetThumbnailsAsync(storage, filePath, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Scope]
|
||||
[Scope(Additional = typeof(DropboxStorageDisposableWrapperExtention))]
|
||||
internal class DropboxStorageDisposableWrapper : IDisposable
|
||||
{
|
||||
public DropboxStorage Storage { get; private set; }
|
||||
@ -163,7 +169,7 @@ internal class DropboxStorageDisposableWrapper : IDisposable
|
||||
|
||||
public async Task<DropboxStorage> InternalCreateStorageAsync(OAuth20Token token, int id)
|
||||
{
|
||||
var dropboxStorage = _serviceProvider.GetService<DropboxStorage>();
|
||||
var dropboxStorage = _serviceProvider.GetRequiredService<DropboxStorage>();
|
||||
|
||||
await CheckTokenAsync(token, id).ConfigureAwait(false);
|
||||
|
||||
@ -311,4 +317,17 @@ public class DropboxProviderInfoHelper
|
||||
await _cacheNotify.PublishAsync(new DropboxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
internal Task<Stream> GetThumbnailsAsync(DropboxStorage storage, string filePath, int width, int height)
|
||||
{
|
||||
return storage.GetThumbnailsAsync(filePath, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DropboxStorageDisposableWrapperExtention
|
||||
{
|
||||
public static void Register(DIHelper dIHelper)
|
||||
{
|
||||
dIHelper.TryAdd<DropboxStorage>();
|
||||
}
|
||||
}
|
@ -24,8 +24,11 @@
|
||||
// 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 ThumbnailSize = Dropbox.Api.Files.ThumbnailSize;
|
||||
|
||||
namespace ASC.Files.Thirdparty.Dropbox;
|
||||
|
||||
[Scope]
|
||||
internal class DropboxStorage : IDisposable
|
||||
{
|
||||
public bool IsOpened { get; private set; }
|
||||
@ -135,10 +138,38 @@ internal class DropboxStorage : IDisposable
|
||||
public async Task<List<Metadata>> GetItemsAsync(string folderPath)
|
||||
{
|
||||
var data = await _dropboxClient.Files.ListFolderAsync(folderPath);
|
||||
|
||||
return new List<Metadata>(data.Entries);
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnailsAsync(string filePath, int width, int height)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = new PathOrLink.Path(filePath);
|
||||
var size = Convert(width, height);
|
||||
var arg = new ThumbnailV2Arg(path, size: size);
|
||||
|
||||
var responce = await _dropboxClient.Files.GetThumbnailV2Async(arg);
|
||||
return await responce.GetContentAsStreamAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ThumbnailSize Convert(int width, int height)
|
||||
{
|
||||
if (width > 368)
|
||||
{
|
||||
return ThumbnailSize.W480h320.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ThumbnailSize.W256h256.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
public Task<Stream> DownloadStreamAsync(string filePath, int offset = 0)
|
||||
{
|
||||
ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(filePath);
|
||||
|
@ -215,6 +215,7 @@ internal abstract class GoogleDriveDaoBase : ThirdPartyProviderDao<GoogleDrivePr
|
||||
file.ModifiedOn = driveFile.ModifiedTime.HasValue ? _tenantUtil.DateTimeFromUtc(driveFile.ModifiedTime.Value) : default;
|
||||
file.NativeAccessor = driveFile;
|
||||
file.Title = MakeFileTitle(driveFile);
|
||||
file.ThumbnailStatus = Thumbnail.Created;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
@ -552,6 +552,12 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public override Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId)), width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
@ -706,5 +712,6 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao<string>
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -158,6 +158,12 @@ internal class GoogleDriveProviderInfo : IProviderInfo
|
||||
{
|
||||
return _googleDriveProviderInfoHelper.CacheResetChildsAsync(ID, parentDriveId, childFolder);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnail(string fileId, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await storage.GetThumbnail(fileId, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Scope(Additional = typeof(GoogleDriveProviderInfoExtention))]
|
||||
|
@ -155,7 +155,6 @@ internal class GoogleDriveStorage : IDisposable
|
||||
try
|
||||
{
|
||||
var request = _driveService.Files.Get(entryId);
|
||||
|
||||
request.Fields = GoogleLoginProvider.FilesFields;
|
||||
|
||||
return await request.ExecuteAsync();
|
||||
@ -170,6 +169,21 @@ internal class GoogleDriveStorage : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnail(string fileId, int width, int height)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = $"https://lh3.google.com/u/0/d/{fileId}=w{width}-h{height}-p-k-nu-iv1";
|
||||
var httpClient = _driveService.HttpClient;
|
||||
var response = await httpClient.GetAsync(url);
|
||||
return await response.Content.ReadAsStreamAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<DriveFile> GetEntries(string folderId, bool? folders = null)
|
||||
{
|
||||
var request = _driveService.Files.List();
|
||||
|
@ -71,13 +71,18 @@ internal abstract class ThirdPartyProviderDao
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public Task SaveThumbnailAsync(File<string> file, Stream thumbnail, int width, int height)
|
||||
public Task SaveThumbnailAsync(File<string> file, Stream thumbnail, int width, int height)
|
||||
{
|
||||
//Do nothing
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<Stream> GetThumbnailAsync(File<string> file, int width, int height)
|
||||
public virtual Task<Stream> GetThumbnailAsync(File<string> file, int width, int height)
|
||||
{
|
||||
return GetThumbnailAsync(file.Id, width, height);
|
||||
}
|
||||
|
||||
public virtual Task<Stream> GetThumbnailAsync(string file, int width, int height)
|
||||
{
|
||||
return Task.FromResult<Stream>(null);
|
||||
}
|
||||
@ -96,7 +101,7 @@ internal abstract class ThirdPartyProviderDao
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public string GetUniqFilePath(File<string> file, string fileTitle)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@ -177,7 +182,7 @@ internal abstract class ThirdPartyProviderDao
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public string GetFolderIDPhotos(bool createIfNotExists)
|
||||
{
|
||||
return null;
|
||||
@ -240,9 +245,9 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
protected List<FilterType> _constraintFolderFilters =
|
||||
new List<FilterType> { FilterType.FilesOnly, FilterType.ByExtension, FilterType.DocumentsOnly, FilterType.ImagesOnly,
|
||||
FilterType.PresentationsOnly, FilterType.SpreadsheetsOnly, FilterType.ArchiveOnly, FilterType.MediaOnly };
|
||||
|
||||
|
||||
protected abstract string Id { get; }
|
||||
|
||||
|
||||
protected ThirdPartyProviderDao(
|
||||
IServiceProvider serviceProvider,
|
||||
UserManager userManager,
|
||||
@ -264,14 +269,14 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
_tempPath = tempPath;
|
||||
TenantID = tenantManager.GetCurrentTenant().Id;
|
||||
}
|
||||
|
||||
|
||||
public void Init(BaseProviderInfo<T> providerInfo, RegexDaoSelectorBase<T> selectorBase)
|
||||
{
|
||||
ProviderInfo = providerInfo.ProviderInfo;
|
||||
PathPrefix = providerInfo.PathPrefix;
|
||||
DaoSelector = selectorBase;
|
||||
}
|
||||
|
||||
|
||||
protected IQueryable<TSet> Query<TSet>(DbSet<TSet> set) where TSet : class, IDbFile
|
||||
{
|
||||
return set.AsQueryable().Where(r => r.TenantId == TenantID);
|
||||
@ -283,7 +288,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return InternalMappingIDAsync(id, saveIfNotExist);
|
||||
}
|
||||
|
||||
@ -311,52 +316,52 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
HashId = result,
|
||||
TenantId = TenantID
|
||||
};
|
||||
|
||||
|
||||
await FilesDbContext.ThirdpartyIdMapping.AddAsync(newMapping).ConfigureAwait(false);
|
||||
await FilesDbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
protected Folder<string> GetFolder()
|
||||
{
|
||||
var folder = _serviceProvider.GetService<Folder<string>>();
|
||||
|
||||
|
||||
InitFileEntry(folder);
|
||||
|
||||
|
||||
folder.FolderType = FolderType.DEFAULT;
|
||||
folder.Shareable = false;
|
||||
folder.FilesCount = 0;
|
||||
folder.FoldersCount = 0;
|
||||
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
protected Folder<string> GetErrorFolder(ErrorEntry entry)
|
||||
{
|
||||
var folder = GetFolder();
|
||||
|
||||
|
||||
InitFileEntryError(folder, entry);
|
||||
|
||||
|
||||
folder.ParentId = null;
|
||||
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
protected File<string> GetFile()
|
||||
{
|
||||
var file = _serviceProvider.GetService<File<string>>();
|
||||
|
||||
|
||||
InitFileEntry(file);
|
||||
|
||||
|
||||
file.Access = FileShare.None;
|
||||
file.Shared = false;
|
||||
file.Version = 1;
|
||||
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
protected File<string> GetErrorFile(ErrorEntry entry)
|
||||
{
|
||||
var file = GetFile();
|
||||
@ -364,7 +369,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
protected void InitFileEntry(FileEntry<string> fileEntry)
|
||||
{
|
||||
fileEntry.CreateBy = ProviderInfo.Owner;
|
||||
@ -375,7 +380,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
fileEntry.RootFolderType = ProviderInfo.RootFolderType;
|
||||
fileEntry.RootId = MakeId();
|
||||
}
|
||||
|
||||
|
||||
protected void InitFileEntryError(FileEntry<string> fileEntry, ErrorEntry entry)
|
||||
{
|
||||
fileEntry.Id = MakeId(entry.ErrorId);
|
||||
@ -406,7 +411,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
|
||||
var filtered = folders.Join(FilesDbContext.ThirdpartyIdMapping.ToAsyncEnumerable(), f => f.Id, m => m.Id, (folder, map) => new { folder, map.HashId })
|
||||
.Join(FilesDbContext.TagLink.ToAsyncEnumerable(), r => r.HashId, t => t.EntryId, (result, tag) => new { result.folder, tag.TagId })
|
||||
.Join(FilesDbContext.Tag.ToAsyncEnumerable(), r => r.TagId, t => t.Id, (result, tagInfo) => new {result.folder, tagInfo.Name })
|
||||
.Join(FilesDbContext.Tag.ToAsyncEnumerable(), r => r.TagId, t => t.Id, (result, tagInfo) => new { result.folder, tagInfo.Name })
|
||||
.Where(r => tagNames.Contains(r.Name))
|
||||
.Select(r => r.folder);
|
||||
|
||||
@ -449,10 +454,10 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<List<FileShareRecord>> GetSharesAsync(IEnumerable<Guid> subjects)
|
||||
public Task<List<FileShareRecord>> GetSharesAsync(IEnumerable<Guid> subjects)
|
||||
{
|
||||
List<FileShareRecord> result = null;
|
||||
return Task<List<FileShareRecord>>.FromResult(result);
|
||||
return Task<List<FileShareRecord>>.FromResult(result);
|
||||
}
|
||||
|
||||
public Task<IEnumerable<FileShareRecord>> GetSharesAsync(IEnumerable<FileEntry<string>> entry)
|
||||
@ -474,7 +479,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Task<IEnumerable<FileShareRecord>> GetPureShareRecordsAsync(FileEntry<string> entry)
|
||||
{
|
||||
return null;
|
||||
@ -553,16 +558,16 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
{
|
||||
return new List<Tag>();
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<Tag> SaveTags(Tag tag)
|
||||
{
|
||||
return new List<Tag>();
|
||||
}
|
||||
|
||||
|
||||
public void UpdateNewTags(IEnumerable<Tag> tag)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public void UpdateNewTags(Tag tag)
|
||||
{
|
||||
}
|
||||
@ -580,7 +585,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
public void RemoveTags(IEnumerable<Tag> tag)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public void RemoveTags(Tag tag)
|
||||
{
|
||||
}
|
||||
@ -589,7 +594,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
{
|
||||
return AsyncEnumerable.Empty<Tag>();
|
||||
}
|
||||
|
||||
|
||||
public void MarkAsNew(Guid subject, FileEntry<string> fileEntry)
|
||||
{
|
||||
}
|
||||
@ -597,24 +602,24 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
public async IAsyncEnumerable<Tag> GetNewTagsAsync(Guid subject, Folder<string> parentFolder, bool deepSearch)
|
||||
{
|
||||
var folderId = DaoSelector.ConvertId(parentFolder.Id);
|
||||
|
||||
|
||||
var entryIDs = await FilesDbContext.ThirdpartyIdMapping
|
||||
.AsQueryable()
|
||||
.Where(r => r.Id.StartsWith(parentFolder.Id))
|
||||
.Select(r => r.HashId)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
|
||||
if (!entryIDs.Any())
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
var q = from r in FilesDbContext.Tag
|
||||
from l in FilesDbContext.TagLink.AsQueryable().Where(a => a.TenantId == r.TenantId && a.TagId == r.Id).DefaultIfEmpty()
|
||||
where r.TenantId == TenantID && l.TenantId == TenantID && r.Type == TagType.New && entryIDs.Contains(l.EntryId)
|
||||
select new { tag = r, tagLink = l };
|
||||
|
||||
|
||||
if (subject != Guid.Empty)
|
||||
{
|
||||
q = q.Where(r => r.tag.Owner == subject);
|
||||
@ -623,7 +628,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
var qList = q
|
||||
.Distinct()
|
||||
.AsAsyncEnumerable();
|
||||
|
||||
|
||||
var tags = qList
|
||||
.SelectAwait(async r => new Tag
|
||||
{
|
||||
@ -636,7 +641,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
Id = r.tag.Id
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (deepSearch)
|
||||
{
|
||||
await foreach (var e in tags.ConfigureAwait(false))
|
||||
@ -646,7 +651,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
var folderFileIds = new[] { parentFolder.Id }
|
||||
.Concat(await GetChildrenAsync(folderId).ConfigureAwait(false));
|
||||
|
||||
@ -659,7 +664,7 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
protected abstract Task<IEnumerable<string>> GetChildrenAsync(string folderId);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (ProviderInfo != null)
|
||||
@ -669,12 +674,12 @@ internal abstract class ThirdPartyProviderDao<T> : ThirdPartyProviderDao, IDispo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class ErrorEntry
|
||||
{
|
||||
public string Error { get; set; }
|
||||
public string ErrorId { get; set; }
|
||||
|
||||
|
||||
public ErrorEntry(string error, string errorId)
|
||||
{
|
||||
Error = error;
|
||||
@ -687,16 +692,16 @@ public class TagLink
|
||||
public int TenantId { get; set; }
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class TagLinkComparer : IEqualityComparer<TagLink>
|
||||
{
|
||||
public bool Equals([AllowNull] TagLink x, [AllowNull] TagLink y)
|
||||
{
|
||||
return x.Id == y.Id && x.TenantId == y.TenantId;
|
||||
}
|
||||
|
||||
|
||||
public int GetHashCode([DisallowNull] TagLink obj)
|
||||
{
|
||||
return obj.Id.GetHashCode() + obj.TenantId.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,6 +192,7 @@ internal abstract class OneDriveDaoBase : ThirdPartyProviderDao<OneDriveProvider
|
||||
file.ModifiedOn = onedriveFile.LastModifiedDateTime.HasValue ? _tenantUtil.DateTimeFromUtc(onedriveFile.LastModifiedDateTime.Value.DateTime) : default;
|
||||
file.NativeAccessor = onedriveFile;
|
||||
file.Title = MakeItemTitle(onedriveFile);
|
||||
file.ThumbnailStatus = Thumbnail.Created;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
@ -561,6 +561,12 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao<string>
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
var oneDriveId = MakeOneDriveId(_oneDriveDaoSelector.ConvertId(fileId));
|
||||
return ProviderInfo.GetThumbnailAsync(oneDriveId, width, height);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
|
||||
private File<string> RestoreIds(File<string> file)
|
||||
|
@ -123,6 +123,12 @@ internal class OneDriveProviderInfo : IProviderInfo
|
||||
{
|
||||
return _oneDriveProviderInfoHelper.CacheResetAsync(ID, onedriveId);
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(string onedriveId, int width, int height)
|
||||
{
|
||||
var storage = await StorageAsync;
|
||||
return await _oneDriveProviderInfoHelper.GetThumbnailAsync(storage, onedriveId, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
[Scope(Additional = typeof(OneDriveProviderInfoExtention))]
|
||||
@ -284,6 +290,11 @@ public class OneDriveProviderInfoHelper
|
||||
_cacheItem.Remove("onedrive-" + i.Key);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<Stream> GetThumbnailAsync(OneDriveStorage storage, string onedriveId, int width, int height)
|
||||
{
|
||||
return await storage.GetThumbnailAsync(onedriveId, width, height).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
public static class OneDriveProviderInfoExtention
|
||||
{
|
||||
|
@ -354,6 +354,30 @@ internal class OneDriveStorage
|
||||
var httpClient = _clientFactory.CreateClient();
|
||||
using var response = await httpClient.SendAsync(request);
|
||||
}
|
||||
|
||||
public async Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
var thumbnails = await OnedriveClient.Drive.Items[fileId].Thumbnails.Request().GetAsync();
|
||||
if (thumbnails.Count > 0)
|
||||
{
|
||||
var url = thumbnails[0].Medium.Url;
|
||||
url = url.Substring(0, url.IndexOf("?width"));
|
||||
url = url + $"?width={width}&height={height}&cropmode=none";
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
RequestUri = new Uri(url),
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
var httpClient = _clientFactory.CreateClient();
|
||||
using var response = await httpClient.SendAsync(request);
|
||||
var bytes = await response.Content.ReadAsByteArrayAsync();
|
||||
return new MemoryStream(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -464,7 +464,7 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
|
||||
var selector = GetSelector(file.Id);
|
||||
var fileDao = selector.GetFileDao(file.Id);
|
||||
|
||||
return fileDao.UseTrashForRemove(file);
|
||||
return fileDao.UseTrashForRemove(file);
|
||||
}
|
||||
|
||||
#region chunking
|
||||
@ -520,5 +520,19 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao<string>
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
public override Task<Stream> GetThumbnailAsync(string fileId, int width, int height)
|
||||
{
|
||||
var selector = GetSelector(fileId);
|
||||
var fileDao = selector.GetFileDao(fileId);
|
||||
return fileDao.GetThumbnailAsync(fileId, width, height);
|
||||
}
|
||||
|
||||
public override Task<Stream> GetThumbnailAsync(File<string> file, int width, int height)
|
||||
{
|
||||
var fileDao = GetFileDao(file);
|
||||
return fileDao.GetThumbnailAsync(file, width, height);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ public class ThumbnailSettings
|
||||
private string _formats;
|
||||
public string Formats
|
||||
{
|
||||
get => _formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docxf|.oform|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.oxps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico";
|
||||
get => _formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docxf|.oform|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.oxps";
|
||||
set => _formats = value;
|
||||
}
|
||||
|
||||
|
@ -27,18 +27,18 @@
|
||||
using JWT.Algorithms;
|
||||
using JWT.Builder;
|
||||
|
||||
using JsonException = System.Text.Json.JsonException;
|
||||
using MimeMapping = ASC.Common.Web.MimeMapping;
|
||||
|
||||
namespace ASC.Web.Files;
|
||||
using JsonException = System.Text.Json.JsonException;
|
||||
using MimeMapping = ASC.Common.Web.MimeMapping;
|
||||
|
||||
namespace ASC.Web.Files;
|
||||
|
||||
public class FileHandler
|
||||
{
|
||||
public FileHandler(RequestDelegate next)
|
||||
public FileHandler(RequestDelegate next)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context, FileHandlerService fileHandlerService)
|
||||
public async Task Invoke(HttpContext context, FileHandlerService fileHandlerService)
|
||||
{
|
||||
await fileHandlerService.Invoke(context).ConfigureAwait(false);
|
||||
}
|
||||
@ -47,7 +47,7 @@ public class FileHandler
|
||||
[Scope]
|
||||
public class FileHandlerService
|
||||
{
|
||||
private readonly ThumbnailSettings _thumbnailSettings;
|
||||
private readonly ThumbnailSettings _thumbnailSettings;
|
||||
|
||||
public string FileHandlerPath
|
||||
{
|
||||
@ -109,10 +109,10 @@ public class FileHandlerService
|
||||
IServiceProvider serviceProvider,
|
||||
TempStream tempStream,
|
||||
SocketManager socketManager,
|
||||
CompressToArchive compressToArchive,
|
||||
InstanceCrypto instanceCrypto,
|
||||
IHttpClientFactory clientFactory,
|
||||
ThumbnailSettings thumbnailSettings)
|
||||
CompressToArchive compressToArchive,
|
||||
InstanceCrypto instanceCrypto,
|
||||
IHttpClientFactory clientFactory,
|
||||
ThumbnailSettings thumbnailSettings)
|
||||
{
|
||||
_filesLinkUtility = filesLinkUtility;
|
||||
_tenantExtra = tenantExtra;
|
||||
@ -142,7 +142,7 @@ public class FileHandlerService
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
_clientFactory = clientFactory;
|
||||
this._thumbnailSettings = thumbnailSettings;
|
||||
this._thumbnailSettings = thumbnailSettings;
|
||||
}
|
||||
|
||||
public Task Invoke(HttpContext context)
|
||||
@ -225,7 +225,7 @@ public class FileHandlerService
|
||||
filename = _instanceCrypto.Decrypt(Uri.UnescapeDataString(filename));
|
||||
}
|
||||
|
||||
var path = string.Format(@"{0}\{1}", _securityContext.CurrentAccount.ID, filename);
|
||||
var path = string.Format(@"{0}\{1}", _securityContext.CurrentAccount.ID, filename);
|
||||
var store = _globalStore.GetStore();
|
||||
|
||||
if (!await store.IsFileAsync(FileConstant.StorageDomainTmp, path))
|
||||
@ -336,7 +336,7 @@ public class FileHandlerService
|
||||
|
||||
if (!await fileDao.IsExistOnStorageAsync(file))
|
||||
{
|
||||
_logger.ErrorDownloadFile2(file.Id.ToString());
|
||||
_logger.ErrorDownloadFile2(file.Id.ToString());
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
|
||||
return;
|
||||
@ -412,7 +412,7 @@ public class FileHandlerService
|
||||
{
|
||||
fileStream = await fileDao.GetFileStreamAsync(file);
|
||||
|
||||
_logger.InformationConvertingToMp4(file.Title, file.Id.ToString());
|
||||
_logger.InformationConvertingToMp4(file.Title, file.Id.ToString());
|
||||
var stream = await _fFmpegService.Convert(fileStream, ext);
|
||||
await store.SaveAsync(string.Empty, mp4Path, stream, mp4Name);
|
||||
}
|
||||
@ -1009,34 +1009,34 @@ public class FileHandlerService
|
||||
}
|
||||
else
|
||||
{
|
||||
await ThumbnailFile(context, q.FirstOrDefault() ?? "");
|
||||
await ThumbnailFileFromThirdparty(context, q.FirstOrDefault() ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ThumbnailFile<T>(HttpContext context, T id)
|
||||
private async Task ThumbnailFile(HttpContext context, int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var defaultSize = _thumbnailSettings.Sizes.FirstOrDefault();
|
||||
|
||||
if (defaultSize == null)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
return;
|
||||
}
|
||||
|
||||
var width = defaultSize.Width;
|
||||
var height = defaultSize.Height;
|
||||
|
||||
var size = context.Request.Query["size"].ToString() ?? "";
|
||||
var sizes = size.Split('x');
|
||||
if (sizes.Length == 2)
|
||||
{
|
||||
_ = int.TryParse(sizes[0], out width);
|
||||
_ = int.TryParse(sizes[1], out height);
|
||||
}
|
||||
|
||||
var fileDao = _daoFactory.GetFileDao<T>();
|
||||
var defaultSize = _thumbnailSettings.Sizes.FirstOrDefault();
|
||||
|
||||
if (defaultSize == null)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
return;
|
||||
}
|
||||
|
||||
var width = defaultSize.Width;
|
||||
var height = defaultSize.Height;
|
||||
|
||||
var size = context.Request.Query["size"].ToString() ?? "";
|
||||
var sizes = size.Split('x');
|
||||
if (sizes.Length == 2)
|
||||
{
|
||||
_ = int.TryParse(sizes[0], out width);
|
||||
_ = int.TryParse(sizes[1], out height);
|
||||
}
|
||||
|
||||
var fileDao = _daoFactory.GetFileDao<int>();
|
||||
var file = int.TryParse(context.Request.Query[FilesLinkUtility.Version], out var version) && version > 0
|
||||
? await fileDao.GetFileAsync(id, version)
|
||||
: await fileDao.GetFileAsync(id);
|
||||
@ -1069,7 +1069,7 @@ public class FileHandlerService
|
||||
context.Response.Headers.Add("Content-Disposition", ContentDispositionUtil.GetHeaderValue("." + _global.ThumbnailExtension));
|
||||
context.Response.ContentType = MimeMapping.GetMimeMapping("." + _global.ThumbnailExtension);
|
||||
|
||||
using (var stream = await fileDao.GetThumbnailAsync(file, width, height))
|
||||
using (var stream = await fileDao.GetThumbnailAsync(file, width, height))
|
||||
{
|
||||
context.Response.Headers.Add("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture));
|
||||
await stream.CopyToAsync(context.Response.Body);
|
||||
@ -1101,9 +1101,68 @@ public class FileHandlerService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ThumbnailFileFromThirdparty(HttpContext context, string id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var defaultSize = _thumbnailSettings.Sizes.FirstOrDefault();
|
||||
|
||||
if (defaultSize == null)
|
||||
{
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
return;
|
||||
}
|
||||
|
||||
var width = defaultSize.Width;
|
||||
var height = defaultSize.Height;
|
||||
|
||||
var size = context.Request.Query["size"].ToString() ?? "";
|
||||
var sizes = size.Split('x');
|
||||
if (sizes.Length == 2)
|
||||
{
|
||||
_ = int.TryParse(sizes[0], out width);
|
||||
_ = int.TryParse(sizes[1], out height);
|
||||
}
|
||||
|
||||
context.Response.Headers.Add("Content-Disposition", ContentDispositionUtil.GetHeaderValue("." + _global.ThumbnailExtension));
|
||||
context.Response.ContentType = MimeMapping.GetMimeMapping("." + _global.ThumbnailExtension);
|
||||
|
||||
var fileDao = _daoFactory.GetFileDao<string>();
|
||||
|
||||
using (var stream = await fileDao.GetThumbnailAsync(id, width, height))
|
||||
{
|
||||
await stream.CopyToAsync(context.Response.Body);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
_logger.ErrorForUrl(context.Request.Url(), ex);
|
||||
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
await context.Response.WriteAsync(ex.Message);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorForUrl(context.Request.Url(), ex);
|
||||
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
await context.Response.WriteAsync(ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await context.Response.Body.FlushAsync();
|
||||
await context.Response.CompleteAsync();
|
||||
}
|
||||
catch (HttpException he)
|
||||
{
|
||||
_logger.ErrorThumbnail(he);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetEtag<T>(File<T> file)
|
||||
{
|
||||
return file.Id + ":" + file.Version + ":" + file.Title.GetHashCode() + ":" + file.ContentLength;
|
||||
return file.Id + ":" + file.Version + ":" + file.Title.GetHashCode() + ":" + file.ContentLength;
|
||||
}
|
||||
|
||||
private Task CreateFile(HttpContext context)
|
||||
@ -1194,33 +1253,33 @@ public class FileHandlerService
|
||||
|
||||
context.Response.Redirect(
|
||||
(context.Request.Query["openfolder"].FirstOrDefault() ?? "").Equals("true")
|
||||
? await _pathProvider.GetFolderUrlByIdAsync(file.ParentId)
|
||||
: (_filesLinkUtility.GetFileWebEditorUrl(file.Id) + "#message/" + HttpUtility.UrlEncode(string.Format(FilesCommonResource.MessageFileCreated, folder.Title))));
|
||||
? await _pathProvider.GetFolderUrlByIdAsync(file.ParentId)
|
||||
: (_filesLinkUtility.GetFileWebEditorUrl(file.Id) + "#message/" + HttpUtility.UrlEncode(string.Format(FilesCommonResource.MessageFileCreated, folder.Title))));
|
||||
}
|
||||
|
||||
private async Task InternalWriteError(HttpContext context, Exception ex, bool responseMessage)
|
||||
{
|
||||
_logger.ErrorFileHandler(ex);
|
||||
|
||||
if (responseMessage)
|
||||
{
|
||||
await context.Response.WriteAsync("error: " + ex.Message);
|
||||
return;
|
||||
}
|
||||
context.Response.Redirect(PathProvider.StartURL + "#error/" + HttpUtility.UrlEncode(ex.Message), true);
|
||||
return;
|
||||
}
|
||||
|
||||
private Task InternalWriteOk<T>(HttpContext context, Folder<T> folder, File<T> file)
|
||||
{
|
||||
var message = string.Format(FilesCommonResource.MessageFileCreated, folder.Title);
|
||||
if (_fileUtility.CanWebRestrictedEditing(file.Title))
|
||||
{
|
||||
message = string.Format(FilesCommonResource.MessageFileCreatedForm, folder.Title);
|
||||
}
|
||||
|
||||
return context.Response.WriteAsync("ok: " + message);
|
||||
}
|
||||
_logger.ErrorFileHandler(ex);
|
||||
|
||||
if (responseMessage)
|
||||
{
|
||||
await context.Response.WriteAsync("error: " + ex.Message);
|
||||
return;
|
||||
}
|
||||
context.Response.Redirect(PathProvider.StartURL + "#error/" + HttpUtility.UrlEncode(ex.Message), true);
|
||||
return;
|
||||
}
|
||||
|
||||
private Task InternalWriteOk<T>(HttpContext context, Folder<T> folder, File<T> file)
|
||||
{
|
||||
var message = string.Format(FilesCommonResource.MessageFileCreated, folder.Title);
|
||||
if (_fileUtility.CanWebRestrictedEditing(file.Title))
|
||||
{
|
||||
message = string.Format(FilesCommonResource.MessageFileCreatedForm, folder.Title);
|
||||
}
|
||||
|
||||
return context.Response.WriteAsync("ok: " + message);
|
||||
}
|
||||
|
||||
private async Task<File<T>> CreateFileFromTemplateAsync<T>(Folder<T> folder, string fileTitle, string docType)
|
||||
{
|
||||
@ -1260,7 +1319,7 @@ public class FileHandlerService
|
||||
|
||||
var file = _serviceProvider.GetService<File<T>>();
|
||||
file.Title = fileTitle;
|
||||
file.ParentId = folder.Id;
|
||||
file.ParentId = folder.Id;
|
||||
file.Comment = FilesCommonResource.CommentCreate;
|
||||
|
||||
var fileDao = _daoFactory.GetFileDao<T>();
|
||||
@ -1278,7 +1337,7 @@ public class FileHandlerService
|
||||
|
||||
var file = _serviceProvider.GetService<File<T>>();
|
||||
file.Title = fileTitle;
|
||||
file.ParentId = folder.Id;
|
||||
file.ParentId = folder.Id;
|
||||
file.Comment = FilesCommonResource.CommentCreate;
|
||||
|
||||
var request = new HttpRequestMessage
|
||||
@ -1351,7 +1410,7 @@ public class FileHandlerService
|
||||
return;
|
||||
}
|
||||
|
||||
urlRedirect = _filesLinkUtility.GetFileWebPreviewUrl(_fileUtility, file.Title, file.Id);
|
||||
urlRedirect = _filesLinkUtility.GetFileWebPreviewUrl(_fileUtility, file.Title, file.Id);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(urlRedirect))
|
||||
@ -1515,4 +1574,4 @@ public static class FileHandlerExtensions
|
||||
{
|
||||
return builder.UseMiddleware<FileHandler>();
|
||||
}
|
||||
}
|
||||
}
|
@ -30,6 +30,9 @@ internal static partial class FFmpegServiceLogger
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "FFmpeg/avconv was not found in PATH or 'files.ffmpeg' setting")]
|
||||
public static partial void ErrorFFmpeg(this ILogger<FFmpegService> logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Information, Message = "FFmpeg found in {path}")]
|
||||
[LoggerMessage(Level = LogLevel.Error, Message = "File {file} not found")]
|
||||
public static partial void ErrorFileNotFound(this ILogger<FFmpegService> logger, string file);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Information, Message = "FFmpeg found in {path}")]
|
||||
public static partial void InformationFFmpegFoundIn(this ILogger<FFmpegService> logger, string path);
|
||||
}
|
||||
|
@ -44,11 +44,25 @@ public class FFmpegService
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<string> _convertableMedia;
|
||||
private readonly List<string> _fFmpegExecutables = new List<string>() { "ffmpeg", "avconv" };
|
||||
private readonly string _fFmpegPath;
|
||||
private readonly string _fFmpegArgs;
|
||||
private readonly string _fFmpegThumbnailsArgs;
|
||||
private readonly List<string> _fFmpegFormats;
|
||||
|
||||
private readonly ILogger<FFmpegService> _logger;
|
||||
|
||||
public bool IsConvertable(string extension)
|
||||
{
|
||||
return MustConvertable.Contains(extension.TrimStart('.'));
|
||||
}
|
||||
|
||||
public bool ExistFormat(string extension)
|
||||
{
|
||||
return _fFmpegFormats.Contains(extension);
|
||||
}
|
||||
|
||||
public Task<Stream> Convert(Stream inputStream, string inputFormat)
|
||||
{
|
||||
if (inputStream == null)
|
||||
@ -68,17 +82,13 @@ public class FFmpegService
|
||||
{
|
||||
var startInfo = PrepareFFmpeg(inputFormat);
|
||||
|
||||
Process process;
|
||||
using (process = new Process { StartInfo = startInfo })
|
||||
{
|
||||
process.Start();
|
||||
using var process = Process.Start(startInfo);
|
||||
|
||||
await StreamCopyToAsync(inputStream, process.StandardInput.BaseStream, closeDst: true);
|
||||
await inputStream.CopyToAsync(process.StandardInput.BaseStream);
|
||||
|
||||
await ProcessLog(process.StandardError.BaseStream);
|
||||
await ProcessLog(process.StandardError.BaseStream);
|
||||
|
||||
return process.StandardOutput.BaseStream;
|
||||
}
|
||||
return process.StandardOutput.BaseStream;
|
||||
}
|
||||
|
||||
public FFmpegService(ILogger<FFmpegService> logger, IConfiguration configuration)
|
||||
@ -86,6 +96,8 @@ public class FFmpegService
|
||||
_logger = logger;
|
||||
_fFmpegPath = configuration["files:ffmpeg:value"];
|
||||
_fFmpegArgs = configuration["files:ffmpeg:args"] ?? "-i - -preset ultrafast -movflags frag_keyframe+empty_moov -f {0} -";
|
||||
_fFmpegThumbnailsArgs = configuration["files:ffmpeg:thumbnails:args"] ?? "-ss 3 -i \"{0}\" -vf \"thumbnail\" -frames:v 1 -vsync vfr \"{1}\" -y";
|
||||
_fFmpegFormats = configuration.GetSection("files:ffmpeg:thumbnails:formats").Get<List<string>>() ?? FileUtility.ExtsVideo;
|
||||
|
||||
_convertableMedia = (configuration.GetSection("files:ffmpeg:exts").Get<string[]>() ?? Array.Empty<string>()).ToList();
|
||||
|
||||
@ -120,13 +132,6 @@ public class FFmpegService
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<string> _convertableMedia;
|
||||
private readonly List<string> _fFmpegExecutables = new List<string>() { "ffmpeg", "avconv" };
|
||||
private readonly string _fFmpegPath;
|
||||
private readonly string _fFmpegArgs;
|
||||
|
||||
private readonly ILogger<FFmpegService> _logger;
|
||||
|
||||
private ProcessStartInfo PrepareFFmpeg(string inputFormat)
|
||||
{
|
||||
if (!_convertableMedia.Contains(inputFormat.TrimStart('.')))
|
||||
@ -134,6 +139,15 @@ public class FFmpegService
|
||||
throw new ArgumentException("input format");
|
||||
}
|
||||
|
||||
var startInfo = PrepareCommonFFmpeg();
|
||||
|
||||
startInfo.Arguments = string.Format(_fFmpegArgs, "mp4");
|
||||
|
||||
return startInfo;
|
||||
}
|
||||
|
||||
private ProcessStartInfo PrepareCommonFFmpeg()
|
||||
{
|
||||
var startInfo = new ProcessStartInfo();
|
||||
|
||||
if (string.IsNullOrEmpty(_fFmpegPath))
|
||||
@ -143,56 +157,15 @@ public class FFmpegService
|
||||
}
|
||||
|
||||
startInfo.FileName = _fFmpegPath;
|
||||
startInfo.WorkingDirectory = Path.GetDirectoryName(_fFmpegPath);
|
||||
startInfo.Arguments = string.Format(_fFmpegArgs, "mp4");
|
||||
startInfo.UseShellExecute = false;
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
startInfo.RedirectStandardInput = true;
|
||||
startInfo.RedirectStandardError = true;
|
||||
startInfo.CreateNoWindow = true;
|
||||
startInfo.WindowStyle = ProcessWindowStyle.Normal;
|
||||
|
||||
return startInfo;
|
||||
}
|
||||
|
||||
private static Task<int> StreamCopyToAsync(Stream srcStream, Stream dstStream, bool closeSrc = false, bool closeDst = false)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(srcStream);
|
||||
ArgumentNullException.ThrowIfNull(dstStream);
|
||||
|
||||
return StreamCopyToAsyncInternal(srcStream, dstStream, closeSrc, closeDst);
|
||||
}
|
||||
|
||||
private static async Task<int> StreamCopyToAsyncInternal(Stream srcStream, Stream dstStream, bool closeSrc, bool closeDst)
|
||||
{
|
||||
const int bufs = 2048 * 4;
|
||||
|
||||
var buffer = new byte[bufs];
|
||||
int readed;
|
||||
var total = 0;
|
||||
while ((readed = await srcStream.ReadAsync(buffer, 0, bufs)) > 0)
|
||||
{
|
||||
await dstStream.WriteAsync(buffer, 0, readed);
|
||||
await dstStream.FlushAsync();
|
||||
total += readed;
|
||||
}
|
||||
|
||||
if (closeSrc)
|
||||
{
|
||||
srcStream.Dispose();
|
||||
srcStream.Close();
|
||||
}
|
||||
|
||||
if (closeDst)
|
||||
{
|
||||
await dstStream.FlushAsync();
|
||||
dstStream.Dispose();
|
||||
dstStream.Close();
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
private async Task ProcessLog(Stream stream)
|
||||
{
|
||||
using var reader = new StreamReader(stream, Encoding.UTF8);
|
||||
@ -202,4 +175,15 @@ public class FFmpegService
|
||||
_logger.Information(line);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateThumbnail(string sourcePath, string destPath)
|
||||
{
|
||||
var startInfo = PrepareCommonFFmpeg();
|
||||
|
||||
startInfo.Arguments = string.Format(_fFmpegThumbnailsArgs, sourcePath, destPath);
|
||||
|
||||
using var process = Process.Start(startInfo);
|
||||
|
||||
await ProcessLog(process.StandardError.BaseStream);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class FilesControllerThirdparty : FilesController<string>
|
||||
_documentServiceHelper = documentServiceHelper;
|
||||
}
|
||||
|
||||
[HttpGet("file/app-{fileId}", Order = int.MaxValue)]
|
||||
[HttpGet("file/app-{fileId}", Order = 1)]
|
||||
public async Task<FileEntryDto> GetFileInfoThirdPartyAsync(string fileId)
|
||||
{
|
||||
fileId = "app-" + fileId;
|
||||
|
@ -104,7 +104,7 @@ public abstract class UploadController<T> : ApiControllerBase
|
||||
/// <param name="keepConvertStatus" visible="false">Keep status conversation after finishing</param>
|
||||
/// <category>Uploads</category>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{folderId}/insert", Order = int.MaxValue)]
|
||||
[HttpPost("{folderId}/insert", Order = 1)]
|
||||
public Task<FileDto<T>> InsertFileAsync(T folderId, [FromForm][ModelBinder(BinderType = typeof(InsertFileModelBinder))] InsertFileRequestDto inDto)
|
||||
{
|
||||
return _filesControllerHelper.InsertFileAsync(folderId, inDto.Stream, inDto.Title, inDto.CreateNewIfExist, inDto.KeepConvertStatus);
|
||||
@ -133,7 +133,7 @@ public abstract class UploadController<T> : ApiControllerBase
|
||||
/// <param name="storeOriginalFileFlag" visible="false">If True, upload documents in original formats as well</param>
|
||||
/// <param name="keepConvertStatus" visible="false">Keep status conversation after finishing</param>
|
||||
/// <returns>Uploaded file</returns>
|
||||
[HttpPost("{folderId}/upload", Order = int.MaxValue)]
|
||||
[HttpPost("{folderId}/upload", Order = 1)]
|
||||
public Task<object> UploadFileAsync(T folderId, [ModelBinder(BinderType = typeof(UploadModelBinder))] UploadRequestDto inDto)
|
||||
{
|
||||
return _filesControllerHelper.UploadFileAsync(folderId, inDto);
|
||||
|
54
products/ASC.Files/Service/Expired/DeleteExpiredService.cs
Normal file
54
products/ASC.Files/Service/Expired/DeleteExpiredService.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// (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.Expired;
|
||||
|
||||
[Singletone]
|
||||
public class DeleteExpiredService : BackgroundService
|
||||
{
|
||||
private readonly CommonChunkedUploadSessionHolder _commonChunkedUploadSessionHolder;
|
||||
private readonly TimeSpan _launchFrequency;
|
||||
|
||||
public DeleteExpiredService(
|
||||
ILogger<DeleteExpiredService> log,
|
||||
SetupInfo setupInfo,
|
||||
TempPath tempPath,
|
||||
GlobalStore globalStore,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
_launchFrequency = TimeSpan.Parse(configuration["files:deleteExpired"] ?? "1", CultureInfo.InvariantCulture);
|
||||
_commonChunkedUploadSessionHolder = new CommonChunkedUploadSessionHolder(tempPath, log, globalStore.GetStore(false), FileConstant.StorageDomainTmp, setupInfo.ChunkUploadSize);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
await _commonChunkedUploadSessionHolder.DeleteExpiredAsync();
|
||||
await Task.Delay(_launchFrequency, stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
@ -24,62 +24,61 @@
|
||||
// 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
|
||||
|
||||
global using System.Collections.Concurrent;
|
||||
global using System.Collections.Concurrent;
|
||||
global using System.Globalization;
|
||||
global using System.Linq.Expressions;
|
||||
global using System.Reflection;
|
||||
global using System.Linq.Expressions;
|
||||
global using System.Reflection;
|
||||
global using System.Text.Json;
|
||||
|
||||
global using ASC.Api.Core;
|
||||
global using ASC.Api.Core.Extensions;
|
||||
global using ASC.Common;
|
||||
global using ASC.Common.Caching;
|
||||
global using ASC.Common.DependencyInjection;
|
||||
global using ASC.Api.Core.Extensions;
|
||||
global using ASC.Common;
|
||||
global using ASC.Common.Caching;
|
||||
global using ASC.Common.DependencyInjection;
|
||||
global using ASC.Common.Log;
|
||||
global using ASC.Common.Mapping;
|
||||
global using ASC.Common.Utils;
|
||||
global using ASC.Core;
|
||||
global using ASC.Core.Common;
|
||||
global using ASC.Core.Common.EF;
|
||||
global using ASC.Core.Common.Hosting;
|
||||
global using ASC.Core.Common.Hosting.Interfaces;
|
||||
global using ASC.Core.Tenants;
|
||||
global using ASC.ElasticSearch;
|
||||
global using ASC.ElasticSearch.Service;
|
||||
global using ASC.Common.Mapping;
|
||||
global using ASC.Core;
|
||||
global using ASC.Core.ChunkedUploader;
|
||||
global using ASC.Core.Common;
|
||||
global using ASC.Core.Common.EF;
|
||||
global using ASC.Core.Common.Hosting;
|
||||
global using ASC.Core.Common.Hosting.Interfaces;
|
||||
global using ASC.Core.Tenants;
|
||||
global using ASC.ElasticSearch;
|
||||
global using ASC.ElasticSearch.Service;
|
||||
global using ASC.EventBus.Abstractions;
|
||||
global using ASC.EventBus.Log;
|
||||
global using ASC.Feed;
|
||||
global using ASC.Feed.Aggregator.Service;
|
||||
global using ASC.Feed;
|
||||
global using ASC.Feed.Aggregator.Service;
|
||||
global using ASC.Feed.Core;
|
||||
global using ASC.Feed.Data;
|
||||
global using ASC.Feed.Data;
|
||||
global using ASC.Files.AutoCleanUp;
|
||||
global using ASC.Files.Core;
|
||||
global using ASC.Files.Core.Core.Entries;
|
||||
global using ASC.Files.Core.EF;
|
||||
global using ASC.Files.Core;
|
||||
global using ASC.Files.Core.Core.Entries;
|
||||
global using ASC.Files.Core.EF;
|
||||
global using ASC.Files.Core.IntegrationEvents.Events;
|
||||
global using ASC.Files.Core.Log;
|
||||
global using ASC.Files.Core.Resources;
|
||||
global using ASC.Files.Core.Security;
|
||||
global using ASC.Files.Core.Log;
|
||||
global using ASC.Files.Core.Resources;
|
||||
global using ASC.Files.Core.Security;
|
||||
global using ASC.Files.Expired;
|
||||
global using ASC.Files.Service.Log;
|
||||
global using ASC.Files.ThumbnailBuilder;
|
||||
global using ASC.Files.ThumbnailBuilder;
|
||||
global using ASC.Thumbnail.IntegrationEvents.EventHandling;
|
||||
global using ASC.Web.Core;
|
||||
global using ASC.Web.Core.Files;
|
||||
global using ASC.Web.Core.Users;
|
||||
global using ASC.Web.Files.Classes;
|
||||
global using ASC.Web.Files.Core;
|
||||
global using ASC.Web.Files.Core.Search;
|
||||
global using ASC.Web.Files.Services.DocumentService;
|
||||
global using ASC.Web.Files.Utils;
|
||||
global using ASC.Web.Studio.Core;
|
||||
global using ASC.Web.Core;
|
||||
global using ASC.Web.Core.Files;
|
||||
global using ASC.Web.Files.Classes;
|
||||
global using ASC.Web.Files.Core.Search;
|
||||
global using ASC.Web.Files.Services.DocumentService;
|
||||
global using ASC.Web.Files.Services.FFmpegService;
|
||||
global using ASC.Web.Files.Utils;
|
||||
global using ASC.Web.Studio.Core;
|
||||
|
||||
global using Autofac;
|
||||
global using Autofac;
|
||||
|
||||
global using Microsoft.AspNetCore.Builder;
|
||||
global using Microsoft.Extensions.Hosting.WindowsServices;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using Microsoft.Extensions.Hosting.WindowsServices;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
|
||||
global using SixLabors.ImageSharp;
|
||||
global using SixLabors.ImageSharp.Formats.Png;
|
||||
global using SixLabors.ImageSharp;
|
||||
|
||||
global using static ASC.Web.Core.Files.DocumentService;
|
@ -82,6 +82,9 @@ builder.Host.ConfigureDefault(args, (hostContext, config, env, path) =>
|
||||
services.AddHostedService<Launcher>();
|
||||
diHelper.TryAdd<Launcher>();
|
||||
|
||||
services.AddHostedService<DeleteExpiredService>();
|
||||
diHelper.TryAdd<DeleteExpiredService>();
|
||||
|
||||
diHelper.TryAdd<AuthManager>();
|
||||
diHelper.TryAdd<BaseCommonLinkUtility>();
|
||||
diHelper.TryAdd<FeedAggregateDataProvider>();
|
||||
|
@ -42,7 +42,7 @@ public class BuilderQueue<T>
|
||||
_config = settings;
|
||||
}
|
||||
|
||||
public async Task BuildThumbnails(IEnumerable<FileData<T>> filesWithoutThumbnails)
|
||||
public async Task BuildThumbnails(IEnumerable<FileData<T>> filesWithoutThumbnails)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -70,18 +70,25 @@ public class BuilderQueue<T>
|
||||
[Scope]
|
||||
public class Builder<T>
|
||||
{
|
||||
private readonly ThumbnailSettings _config;
|
||||
private readonly ILogger _logger;
|
||||
private readonly TenantManager _tenantManager;
|
||||
private readonly IDaoFactory _daoFactory;
|
||||
private readonly DocumentServiceConnector _documentServiceConnector;
|
||||
private readonly DocumentServiceHelper _documentServiceHelper;
|
||||
private readonly Global _global;
|
||||
private readonly PathProvider _pathProvider;
|
||||
private readonly ThumbnailSettings _config;
|
||||
private readonly ILogger _logger;
|
||||
private readonly TenantManager _tenantManager;
|
||||
private readonly IDaoFactory _daoFactory;
|
||||
private readonly DocumentServiceConnector _documentServiceConnector;
|
||||
private readonly DocumentServiceHelper _documentServiceHelper;
|
||||
private readonly Global _global;
|
||||
private readonly PathProvider _pathProvider;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
private readonly ThumbnailSettings _thumbnailSettings;
|
||||
private readonly SocketManager _socketManager;
|
||||
|
||||
private readonly SocketManager _socketManager;
|
||||
private readonly FFmpegService _fFmpegService;
|
||||
private readonly TempPath _tempPath;
|
||||
|
||||
private readonly List<string> _imageFormatsCanBeCrop = new List<string>
|
||||
{
|
||||
".bmp", ".gif", ".jpeg", ".jpg", ".pbm", ".png", ".tiff", ".tga", ".webp",
|
||||
};
|
||||
|
||||
public Builder(
|
||||
ThumbnailSettings settings,
|
||||
TenantManager tenantManager,
|
||||
@ -92,8 +99,10 @@ public class Builder<T>
|
||||
PathProvider pathProvider,
|
||||
ILoggerProvider log,
|
||||
IHttpClientFactory clientFactory,
|
||||
FFmpegService fFmpegService,
|
||||
TempPath tempPath,
|
||||
SocketManager socketManager,
|
||||
ThumbnailSettings thumbnailSettings)
|
||||
ThumbnailSettings thumbnailSettings)
|
||||
{
|
||||
_config = settings;
|
||||
_tenantManager = tenantManager;
|
||||
@ -104,11 +113,13 @@ public class Builder<T>
|
||||
_pathProvider = pathProvider;
|
||||
_logger = log.CreateLogger("ASC.Files.ThumbnailBuilder");
|
||||
_clientFactory = clientFactory;
|
||||
_fFmpegService = fFmpegService;
|
||||
_tempPath = tempPath;
|
||||
_socketManager = socketManager;
|
||||
_thumbnailSettings = thumbnailSettings;
|
||||
}
|
||||
|
||||
internal async Task BuildThumbnail(FileData<T> fileData)
|
||||
internal async Task BuildThumbnail(FileData<T> fileData)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -122,7 +133,7 @@ public class Builder<T>
|
||||
return;
|
||||
}
|
||||
|
||||
await GenerateThumbnail(fileDao, fileData);
|
||||
await GenerateThumbnail(fileDao, fileData);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@ -134,13 +145,13 @@ public class Builder<T>
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GenerateThumbnail(IFileDao<T> fileDao, FileData<T> fileData)
|
||||
private async Task GenerateThumbnail(IFileDao<T> fileDao, FileData<T> fileData)
|
||||
{
|
||||
File<T> file = null;
|
||||
|
||||
try
|
||||
{
|
||||
file = await fileDao.GetFileAsync(fileData.FileId);
|
||||
file = await fileDao.GetFileAsync(fileData.FileId);
|
||||
|
||||
if (file == null)
|
||||
{
|
||||
@ -158,29 +169,37 @@ public class Builder<T>
|
||||
|
||||
var ext = FileUtility.GetFileExtension(file.Title);
|
||||
|
||||
if (!_config.FormatsArray.Contains(ext) || file.Encrypted || file.RootFolderType == FolderType.TRASH || file.ContentLength > _config.AvailableFileSize)
|
||||
if (!CanCreateThumbnail(ext) || file.Encrypted || file.RootFolderType == FolderType.TRASH || file.ContentLength > _config.AvailableFileSize)
|
||||
{
|
||||
file.ThumbnailStatus = ASC.Files.Core.Thumbnail.NotRequired;
|
||||
foreach (var size in _thumbnailSettings.Sizes)
|
||||
{
|
||||
await fileDao.SaveThumbnailAsync(file, null, size.Width, size.Height);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsImage(file))
|
||||
if (IsVideo(ext))
|
||||
{
|
||||
await CropImage(fileDao, file);
|
||||
await MakeThumbnailFromVideo(fileDao, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
await MakeThumbnail(fileDao, file);
|
||||
|
||||
if (IsImage(ext))
|
||||
{
|
||||
await CropImage(fileDao, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
await MakeThumbnail(fileDao, file);
|
||||
}
|
||||
}
|
||||
|
||||
var newFile = await fileDao.GetFileStableAsync(file.Id);
|
||||
|
||||
await _socketManager.UpdateFileAsync(newFile);
|
||||
await _socketManager.UpdateFileAsync(newFile);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@ -194,9 +213,32 @@ public class Builder<T>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MakeThumbnail(IFileDao<T> fileDao, File<T> file)
|
||||
private async Task MakeThumbnailFromVideo(IFileDao<T> fileDao, File<T> file)
|
||||
{
|
||||
var streamFile = await fileDao.GetFileStreamAsync(file);
|
||||
|
||||
var thumbPath = _tempPath.GetTempFileName("jpg");
|
||||
var tempFilePath = _tempPath.GetTempFileName(Path.GetExtension(file.Title));
|
||||
|
||||
using (var fileStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.ReadWrite, System.IO.FileShare.Read))
|
||||
{
|
||||
await streamFile.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
await _fFmpegService.CreateThumbnail(tempFilePath, thumbPath);
|
||||
|
||||
using (var streamThumb = new FileStream(thumbPath, FileMode.Open, FileAccess.ReadWrite, System.IO.FileShare.Read))
|
||||
{
|
||||
await Crop(fileDao, file, streamThumb);
|
||||
}
|
||||
|
||||
File.Delete(thumbPath);
|
||||
File.Delete(tempFilePath);
|
||||
}
|
||||
|
||||
private async Task MakeThumbnail(IFileDao<T> fileDao, File<T> file)
|
||||
{
|
||||
foreach (var w in _config.Sizes)
|
||||
{
|
||||
@ -254,7 +296,7 @@ public class Builder<T>
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<(bool, string)> GetThumbnailUrl(File<T> file, string toExtension, int width, int height)
|
||||
private async Task<(bool, string)> GetThumbnailUrl(File<T> file, string toExtension, int width, int height)
|
||||
{
|
||||
var fileUri = _pathProvider.GetFileStreamUrl(file);
|
||||
fileUri = _documentServiceConnector.ReplaceCommunityAdress(fileUri);
|
||||
@ -273,7 +315,7 @@ public class Builder<T>
|
||||
IgnorePrintArea = true,
|
||||
//Orientation = "landscape", // "297mm" x "210mm"
|
||||
FitToHeight = height,
|
||||
FitToWidth = width,
|
||||
FitToWidth = width,
|
||||
Headings = false,
|
||||
GridLines = false,
|
||||
Margins = new DocumentService.SpreadsheetLayout.LayoutMargins
|
||||
@ -288,54 +330,62 @@ public class Builder<T>
|
||||
}
|
||||
};
|
||||
|
||||
var (operationResultProgress, url) = await _documentServiceConnector.GetConvertedUriAsync(fileUri, fileExtension, toExtension, docKey, null, CultureInfo.CurrentCulture.Name, thumbnail, spreadsheetLayout, false);
|
||||
var (operationResultProgress, url) = await _documentServiceConnector.GetConvertedUriAsync(fileUri, fileExtension, toExtension, docKey, null, CultureInfo.CurrentCulture.Name, thumbnail, spreadsheetLayout, false);
|
||||
|
||||
operationResultProgress = Math.Min(operationResultProgress, 100);
|
||||
return (operationResultProgress == 100, url);
|
||||
return (operationResultProgress == 100, url);
|
||||
}
|
||||
|
||||
private async Task SaveThumbnail(IFileDao<T> fileDao, File<T> file, string thumbnailUrl, int width, int height)
|
||||
private async Task SaveThumbnail(IFileDao<T> fileDao, File<T> file, string thumbnailUrl, int width, int height)
|
||||
{
|
||||
_logger.DebugMakeThumbnail3(file.Id.ToString(), thumbnailUrl);
|
||||
|
||||
using var request = new HttpRequestMessage();
|
||||
using var request = new HttpRequestMessage();
|
||||
request.RequestUri = new Uri(thumbnailUrl);
|
||||
|
||||
var httpClient = _clientFactory.CreateClient();
|
||||
using var response = httpClient.Send(request);
|
||||
using (var stream = await response.Content.ReadAsStreamAsync())
|
||||
using (var stream = await response.Content.ReadAsStreamAsync())
|
||||
{
|
||||
using (var sourceImg = await Image.LoadAsync(stream))
|
||||
{
|
||||
await CropAsync(sourceImg, fileDao, file, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.DebugMakeThumbnail4(file.Id.ToString());
|
||||
}
|
||||
|
||||
private bool IsImage(File<T> file)
|
||||
private bool CanCreateThumbnail(string extention)
|
||||
{
|
||||
var extension = FileUtility.GetFileExtension(file.Title);
|
||||
|
||||
return FileUtility.ExtsImage.Contains(extension);
|
||||
return _config.FormatsArray.Contains(extention) || IsVideo(extention) || IsImage(extention);
|
||||
}
|
||||
|
||||
private async Task CropImage(IFileDao<T> fileDao, File<T> file)
|
||||
private bool IsImage(string extention)
|
||||
{
|
||||
return _imageFormatsCanBeCrop.Contains(extention);
|
||||
}
|
||||
|
||||
private bool IsVideo(string extention)
|
||||
{
|
||||
return _fFmpegService.ExistFormat(extention);
|
||||
}
|
||||
|
||||
private async Task CropImage(IFileDao<T> fileDao, File<T> file)
|
||||
{
|
||||
_logger.DebugCropImage(file.Id.ToString());
|
||||
|
||||
using (var stream = await fileDao.GetFileStreamAsync(file))
|
||||
using (var stream = await fileDao.GetFileStreamAsync(file))
|
||||
{
|
||||
await Crop(fileDao, file, stream);
|
||||
await Crop(fileDao, file, stream);
|
||||
}
|
||||
|
||||
_logger.DebugCropImageSuccessfullySaved(file.Id.ToString());
|
||||
}
|
||||
|
||||
private async Task Crop(IFileDao<T> fileDao, File<T> file, Stream stream)
|
||||
private async Task Crop(IFileDao<T> fileDao, File<T> file, Stream stream)
|
||||
{
|
||||
using (var sourceImg = await Image.LoadAsync(stream))
|
||||
using (var sourceImg = await Image.LoadAsync(stream))
|
||||
{
|
||||
//var tasks = new List<Task>();
|
||||
|
||||
@ -357,12 +407,11 @@ public class Builder<T>
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
private async ValueTask CropAsync(Image sourceImg, IFileDao<T> fileDao, File<T> file, int width, int height)
|
||||
private async ValueTask CropAsync(Image sourceImg, IFileDao<T> fileDao, File<T> file, int width, int height)
|
||||
{
|
||||
var targetSize = new Size(Math.Min(sourceImg.Width, width), Math.Min(sourceImg.Height, height));
|
||||
using var targetImg = GetImageThumbnail(sourceImg, targetSize, width, height);
|
||||
using var targetImg = GetImageThumbnail(sourceImg, width);
|
||||
using var targetStream = new MemoryStream();
|
||||
switch (_global.ThumbnailExtension)
|
||||
switch (_global.ThumbnailExtension)
|
||||
{
|
||||
case ThumbnailExtension.bmp:
|
||||
await targetImg.SaveAsBmpAsync(targetStream);
|
||||
@ -392,8 +441,8 @@ public class Builder<T>
|
||||
await fileDao.SaveThumbnailAsync(file, targetStream, width, height);
|
||||
}
|
||||
|
||||
private Image GetImageThumbnail(Image sourceBitmap, Size targetSize, int thumbnaillWidth, int thumbnaillHeight)
|
||||
private Image GetImageThumbnail(Image sourceBitmap, int thumbnaillWidth)
|
||||
{
|
||||
return sourceBitmap.Clone(x => x.BackgroundColor(Color.White).Resize(thumbnaillWidth, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public class AuthenticationController : ControllerBase
|
||||
}
|
||||
|
||||
[AllowNotPayment]
|
||||
[HttpPost("{code}", Order = int.MaxValue)]
|
||||
[HttpPost("{code}", Order = 1)]
|
||||
public AuthenticationTokenDto AuthenticateMeFromBodyWithCode(AuthRequestsDto inDto)
|
||||
{
|
||||
var tenant = _tenantManager.GetCurrentTenant().Id;
|
||||
|
Loading…
Reference in New Issue
Block a user