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;
|
||||
|
@ -287,6 +287,8 @@ public interface IFileDao<T>
|
||||
|
||||
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);
|
||||
|
@ -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();
|
||||
|
@ -77,7 +77,12 @@ internal abstract class ThirdPartyProviderDao
|
||||
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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1009,11 +1009,11 @@ 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
|
||||
{
|
||||
@ -1036,7 +1036,7 @@ public class FileHandlerService
|
||||
_ = int.TryParse(sizes[1], out height);
|
||||
}
|
||||
|
||||
var fileDao = _daoFactory.GetFileDao<T>();
|
||||
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);
|
||||
@ -1101,6 +1101,65 @@ 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;
|
||||
|
@ -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.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,24 +82,22 @@ 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);
|
||||
|
||||
return process.StandardOutput.BaseStream;
|
||||
}
|
||||
}
|
||||
|
||||
public FFmpegService(ILogger<FFmpegService> logger, IConfiguration configuration)
|
||||
{
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
@ -37,8 +37,8 @@ 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.ChunkedUploader;
|
||||
global using ASC.Core.Common;
|
||||
global using ASC.Core.Common.EF;
|
||||
global using ASC.Core.Common.Hosting;
|
||||
@ -60,16 +60,16 @@ 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.Expired;
|
||||
global using ASC.Files.Service.Log;
|
||||
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.Services.FFmpegService;
|
||||
global using ASC.Web.Files.Utils;
|
||||
global using ASC.Web.Studio.Core;
|
||||
|
||||
@ -80,6 +80,5 @@ global using Microsoft.Extensions.Hosting.WindowsServices;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
|
||||
global using SixLabors.ImageSharp;
|
||||
global using SixLabors.ImageSharp.Formats.Png;
|
||||
|
||||
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>();
|
||||
|
@ -81,6 +81,13 @@ public class Builder<T>
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
private readonly ThumbnailSettings _thumbnailSettings;
|
||||
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,
|
||||
@ -92,6 +99,8 @@ public class Builder<T>
|
||||
PathProvider pathProvider,
|
||||
ILoggerProvider log,
|
||||
IHttpClientFactory clientFactory,
|
||||
FFmpegService fFmpegService,
|
||||
TempPath tempPath,
|
||||
SocketManager socketManager,
|
||||
ThumbnailSettings thumbnailSettings)
|
||||
{
|
||||
@ -104,6 +113,8 @@ public class Builder<T>
|
||||
_pathProvider = pathProvider;
|
||||
_logger = log.CreateLogger("ASC.Files.ThumbnailBuilder");
|
||||
_clientFactory = clientFactory;
|
||||
_fFmpegService = fFmpegService;
|
||||
_tempPath = tempPath;
|
||||
_socketManager = socketManager;
|
||||
_thumbnailSettings = thumbnailSettings;
|
||||
}
|
||||
@ -158,7 +169,7 @@ 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)
|
||||
@ -169,7 +180,14 @@ public class Builder<T>
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsImage(file))
|
||||
if (IsVideo(ext))
|
||||
{
|
||||
await MakeThumbnailFromVideo(fileDao, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (IsImage(ext))
|
||||
{
|
||||
await CropImage(fileDao, file);
|
||||
}
|
||||
@ -177,6 +195,7 @@ public class Builder<T>
|
||||
{
|
||||
await MakeThumbnail(fileDao, file);
|
||||
}
|
||||
}
|
||||
|
||||
var newFile = await fileDao.GetFileStableAsync(file.Id);
|
||||
|
||||
@ -196,6 +215,29 @@ public class Builder<T>
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@ -314,11 +356,19 @@ public class Builder<T>
|
||||
_logger.DebugMakeThumbnail4(file.Id.ToString());
|
||||
}
|
||||
|
||||
private bool IsImage(File<T> file)
|
||||
private bool CanCreateThumbnail(string extention)
|
||||
{
|
||||
var extension = FileUtility.GetFileExtension(file.Title);
|
||||
return _config.FormatsArray.Contains(extention) || IsVideo(extention) || IsImage(extention);
|
||||
}
|
||||
|
||||
return FileUtility.ExtsImage.Contains(extension);
|
||||
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)
|
||||
@ -359,8 +409,7 @@ public class Builder<T>
|
||||
|
||||
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)
|
||||
{
|
||||
@ -392,7 +441,7 @@ 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