// (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.Api; [ConstraintRoute("int")] public class FilesControllerInternal : FilesController { public FilesControllerInternal( FilesControllerHelper filesControllerHelper, FileStorageService fileStorageService, IMapper mapper, FileOperationDtoHelper fileOperationDtoHelper, FolderDtoHelper folderDtoHelper, FileDtoHelper fileDtoHelper) : base(filesControllerHelper, fileStorageService, mapper, fileOperationDtoHelper, folderDtoHelper, fileDtoHelper) { } } public class FilesControllerThirdparty : FilesController { private readonly ThirdPartySelector _thirdPartySelector; private readonly DocumentServiceHelper _documentServiceHelper; public FilesControllerThirdparty( FilesControllerHelper filesControllerHelper, FileStorageService fileStorageService, ThirdPartySelector thirdPartySelector, DocumentServiceHelper documentServiceHelper, IMapper mapper, FileOperationDtoHelper fileOperationDtoHelper, FolderDtoHelper folderDtoHelper, FileDtoHelper fileDtoHelper) : base(filesControllerHelper, fileStorageService, mapper, fileOperationDtoHelper, folderDtoHelper, fileDtoHelper) { _thirdPartySelector = thirdPartySelector; _documentServiceHelper = documentServiceHelper; } [HttpGet("file/app-{fileId}", Order = 1)] public async Task GetFileInfoThirdPartyAsync(string fileId) { fileId = "app-" + fileId; var app = _thirdPartySelector.GetAppByFileId(fileId?.ToString()); var file = app.GetFile(fileId?.ToString(), out var editable); var docParams = await _documentServiceHelper.GetParamsAsync(file, true, editable ? FileShare.ReadWrite : FileShare.Read, false, editable, editable, editable, false); return await GetFileEntryWrapperAsync(docParams.File); } } public abstract class FilesController : ApiControllerBase { protected readonly FilesControllerHelper _filesControllerHelper; private readonly FileStorageService _fileStorageService; private readonly IMapper _mapper; private readonly FileOperationDtoHelper _fileOperationDtoHelper; public FilesController( FilesControllerHelper filesControllerHelper, FileStorageService fileStorageService, IMapper mapper, FileOperationDtoHelper fileOperationDtoHelper, FolderDtoHelper folderDtoHelper, FileDtoHelper fileDtoHelper) : base(folderDtoHelper, fileDtoHelper) { _filesControllerHelper = filesControllerHelper; _fileStorageService = fileStorageService; _mapper = mapper; _fileOperationDtoHelper = fileOperationDtoHelper; } /// /// Change version history /// /// File ID /// Version of history /// Mark as version or revision /// Files /// [HttpPut("file/{fileId}/history")] public IAsyncEnumerable> ChangeHistoryAsync(T fileId, ChangeHistoryRequestDto inDto) { return _filesControllerHelper.ChangeHistoryAsync(fileId, inDto.Version, inDto.ContinueVersion); } /// /// Check conversion status /// /// Convert /// File operations /// /// /// Operation result [HttpGet("file/{fileId}/checkconversion")] public IAsyncEnumerable> CheckConversionAsync(T fileId, bool start) { return _filesControllerHelper.CheckConversionAsync(new CheckConversionRequestDto() { FileId = fileId, StartConvert = start }); } [HttpGet("file/{fileId}/presigneduri")] public async Task GetPresignedUri(T fileId) { return await _filesControllerHelper.GetPresignedUri(fileId); } [HttpPost("file/{fileId}/copyas")] public async Task CopyFileAs(T fileId, CopyAsRequestDto inDto) { if (inDto.DestFolderId.ValueKind == JsonValueKind.Number) { return await _filesControllerHelper.CopyFileAsAsync(fileId, inDto.DestFolderId.GetInt32(), inDto.DestTitle, inDto.Password); } else if (inDto.DestFolderId.ValueKind == JsonValueKind.String) { return await _filesControllerHelper.CopyFileAsAsync(fileId, inDto.DestFolderId.GetString(), inDto.DestTitle, inDto.Password); } return null; } /// /// Creates a new file in the specified folder with the title sent in the request /// /// Create file /// File Creation /// Folder ID /// File title /// In case the extension for the file title differs from DOCX/XLSX/PPTX and belongs to one of the known text, spreadsheet or presentation formats, it will be changed to DOCX/XLSX/PPTX accordingly. If the file extension is not set or is unknown, the DOCX extension will be added to the file title. /// New file info [HttpPost("{folderId}/file")] public Task> CreateFileAsync(T folderId, CreateFileRequestDto inDto) { return _filesControllerHelper.CreateFileAsync(folderId, inDto.Title, inDto.TemplateId, inDto.FormId, inDto.EnableExternalExt); } /// /// Creates an html (.html) file in the selected folder with the title and contents sent in the request /// /// Create html /// File Creation /// Folder ID /// File title /// File contents /// Folder contents [HttpPost("{folderId}/html")] public Task> CreateHtmlFileAsync(T folderId, CreateTextOrHtmlFileRequestDto inDto) { return _filesControllerHelper.CreateHtmlFileAsync(folderId, inDto.Title, inDto.Content); } /// /// Creates a text (.txt) file in the selected folder with the title and contents sent in the request /// /// Create txt /// File Creation /// Folder ID /// File title /// File contents /// Folder contents [HttpPost("{folderId}/text")] public Task> CreateTextFileAsync(T folderId, CreateTextOrHtmlFileRequestDto inDto) { return _filesControllerHelper.CreateTextFileAsync(folderId, inDto.Title, inDto.Content); } /// /// Deletes the file with the ID specified in the request /// /// Delete file /// Files /// File ID /// Delete after finished /// Don't move to the Recycle Bin /// Operation result [HttpDelete("file/{fileId}")] public async IAsyncEnumerable DeleteFile(T fileId, [FromBody] DeleteRequestDto inDto) { foreach (var e in _fileStorageService.DeleteFile("delete", fileId, false, inDto.DeleteAfter, inDto.Immediately)) { yield return await _fileOperationDtoHelper.GetAsync(e); } } [AllowAnonymous] [HttpGet("file/{fileId}/edit/diff")] public Task GetEditDiffUrlAsync(T fileId, int version = 0, string doc = null) { return _filesControllerHelper.GetEditDiffUrlAsync(fileId, version, doc); } [AllowAnonymous] [HttpGet("file/{fileId}/edit/history")] public IAsyncEnumerable GetEditHistoryAsync(T fileId, string doc = null) { return _filesControllerHelper.GetEditHistoryAsync(fileId, doc); } /// /// Returns a detailed information about the file with the ID specified in the request /// /// File information /// Files /// File info [HttpGet("file/{fileId}")] public Task> GetFileInfoAsync(T fileId, int version = -1) { return _filesControllerHelper.GetFileInfoAsync(fileId, version); } /// /// Returns the detailed information about all the available file versions with the ID specified in the request /// /// File versions /// Files /// File ID /// File information [HttpGet("file/{fileId}/history")] public IAsyncEnumerable> GetFileVersionInfoAsync(T fileId) { return _filesControllerHelper.GetFileVersionInfoAsync(fileId); } [HttpPut("file/{fileId}/lock")] public Task> LockFileAsync(T fileId, LockFileRequestDto inDto) { return _filesControllerHelper.LockFileAsync(fileId, inDto.LockFile); } [AllowAnonymous] [HttpGet("file/{fileId}/restoreversion")] public IAsyncEnumerable RestoreVersionAsync(T fileId, int version = 0, string url = null, string doc = null) { return _filesControllerHelper.RestoreVersionAsync(fileId, version, url, doc); } /// /// Start conversion /// /// Convert /// File operations /// /// Operation result [HttpPut("file/{fileId}/checkconversion")] public IAsyncEnumerable> StartConversion(T fileId, [FromBody(EmptyBodyBehavior = Microsoft.AspNetCore.Mvc.ModelBinding.EmptyBodyBehavior.Allow)] CheckConversionRequestDto inDto) { if (inDto == null) { inDto = new CheckConversionRequestDto(); } inDto.FileId = fileId; return _filesControllerHelper.StartConversionAsync(inDto); } [HttpPut("file/{fileId}/comment")] public async Task UpdateCommentAsync(T fileId, UpdateCommentRequestDto inDto) { return await _filesControllerHelper.UpdateCommentAsync(fileId, inDto.Version, inDto.Comment); } /// /// Updates the information of the selected file with the parameters specified in the request /// /// Update file info /// Files /// File ID /// New title /// File last version number /// File info [HttpPut("file/{fileId}")] public Task> UpdateFileAsync(T fileId, UpdateFileRequestDto inDto) { return _filesControllerHelper.UpdateFileAsync(fileId, inDto.Title, inDto.LastVersion); } /// /// /// /// /// /// /// /// false [HttpPut("{fileId}/update")] public Task> UpdateFileStreamFromFormAsync(T fileId, [FromForm] FileStreamRequestDto inDto) { return _filesControllerHelper.UpdateFileStreamAsync(_filesControllerHelper.GetFileFromRequest(inDto).OpenReadStream(), fileId, inDto.FileExtension, inDto.Encrypted, inDto.Forcesave); } [HttpGet("{fileId}/properties")] public async Task GetProperties(T fileId) { return _mapper.Map(await _fileStorageService.GetFileProperties(fileId)); } [HttpPut("{fileId}/properties")] public Task SetProperties(T fileId, EntryPropertiesRequestDto fileProperties) { return _fileStorageService.SetFileProperties(fileId, _mapper.Map(fileProperties)); } } public class FilesControllerCommon : ApiControllerBase { private readonly IMapper _mapper; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly GlobalFolderHelper _globalFolderHelper; private readonly FileStorageService _fileStorageServiceThirdparty; private readonly FilesControllerHelper _filesControllerHelperInternal; public FilesControllerCommon( IMapper mapper, IServiceScopeFactory serviceScopeFactory, GlobalFolderHelper globalFolderHelper, FileStorageService fileStorageServiceThirdparty, FilesControllerHelper filesControllerHelperInternal, FolderDtoHelper folderDtoHelper, FileDtoHelper fileDtoHelper) : base(folderDtoHelper, fileDtoHelper) { _mapper = mapper; _serviceScopeFactory = serviceScopeFactory; _globalFolderHelper = globalFolderHelper; _fileStorageServiceThirdparty = fileStorageServiceThirdparty; _filesControllerHelperInternal = filesControllerHelperInternal; } /// /// Creates a new file in the 'My Documents' section with the title sent in the request /// /// Create file /// File Creation /// File title /// In case the extension for the file title differs from DOCX/XLSX/PPTX and belongs to one of the known text, spreadsheet or presentation formats, it will be changed to DOCX/XLSX/PPTX accordingly. If the file extension is not set or is unknown, the DOCX extension will be added to the file title. /// New file info [HttpPost("@my/file")] public Task> CreateFileAsync(CreateFileRequestDto inDto) { return _filesControllerHelperInternal.CreateFileAsync(_globalFolderHelper.FolderMy, inDto.Title, inDto.TemplateId, inDto.FormId, inDto.EnableExternalExt); } /// /// Creates an html (.html) file in 'Common Documents' section with the title and contents sent in the request /// /// Create html in 'Common' /// File Creation /// File title /// File contents /// Folder contents [HttpPost("@common/html")] public async Task> CreateHtmlFileInCommonAsync(CreateTextOrHtmlFileRequestDto inDto) { return await _filesControllerHelperInternal.CreateHtmlFileAsync(await _globalFolderHelper.FolderCommonAsync, inDto.Title, inDto.Content); } /// /// Creates an html (.html) file in 'My Documents' section with the title and contents sent in the request /// /// Create html in 'My' /// File Creation /// File title /// File contents /// Folder contents [HttpPost("@my/html")] public Task> CreateHtmlFileInMyAsync(CreateTextOrHtmlFileRequestDto inDto) { return _filesControllerHelperInternal.CreateHtmlFileAsync(_globalFolderHelper.FolderMy, inDto.Title, inDto.Content); } /// /// Creates a text (.txt) file in 'Common Documents' section with the title and contents sent in the request /// /// Create txt in 'Common' /// File Creation /// File title /// File contents /// Folder contents [HttpPost("@common/text")] public async Task> CreateTextFileInCommonAsync(CreateTextOrHtmlFileRequestDto inDto) { return await _filesControllerHelperInternal.CreateTextFileAsync(await _globalFolderHelper.FolderCommonAsync, inDto.Title, inDto.Content); } /// /// Creates a text (.txt) file in 'My Documents' section with the title and contents sent in the request /// /// Create txt in 'My' /// File Creation /// File title /// File contents /// Folder contents [HttpPost("@my/text")] public Task> CreateTextFileInMyAsync(CreateTextOrHtmlFileRequestDto inDto) { return _filesControllerHelperInternal.CreateTextFileAsync(_globalFolderHelper.FolderMy, inDto.Title, inDto.Content); } [HttpPost("thumbnails")] public Task> CreateThumbnailsAsync(BaseBatchRequestDto inDto) { return _fileStorageServiceThirdparty.CreateThumbnailsAsync(inDto.FileIds.ToList()); } [HttpPut("batch/properties")] public async Task> SetProperties(BatchEntryPropertiesRequestDto batchEntryPropertiesRequestDto) { var result = new List(); foreach (var fileId in batchEntryPropertiesRequestDto.FilesId) { if (fileId.ValueKind == JsonValueKind.String) { await AddProps(fileId.GetString()); } else if (fileId.ValueKind == JsonValueKind.String) { await AddProps(fileId.GetInt32()); } } return result; async Task AddProps(T fileId) { using var scope = _serviceScopeFactory.CreateScope(); var fileStorageService = scope.ServiceProvider.GetRequiredService>(); var props = _mapper.Map(batchEntryPropertiesRequestDto.FileProperties); if (batchEntryPropertiesRequestDto.CreateSubfolder) { var file = await fileStorageService.GetFileAsync(fileId, -1).NotFoundIfNull("File not found"); props.FormFilling.CreateFolderTitle = Path.GetFileNameWithoutExtension(file.Title); } result.Add(await fileStorageService.SetFileProperties(fileId, props)); } } }